Microsoft.Practices.Unity入門

Unity是微軟Patterns & Practices團隊所開發的一個輕量級的,而且可擴展的依賴注入(Dependency Injection)容器,它支持經常使用的三種依賴注入方式:構造器注入(Constructor Injection)、屬性注入(Property Injection),以及方法調用注入(Method Call Injection).如今Unity最新的版本的1.2版,能夠在微軟的開源站點http://unity.codeplex.com下載最新的發佈版本和文檔。經過使用Unity,咱們能輕鬆構建鬆耦合結構的程序,從而讓整個程序框架變得清晰和易於維護。編程

在日常的軟件編碼過程當中,程序的邏輯每每很複雜,尤爲是大型項目的開發中,一個模塊經常會去引用其餘的模塊,假設咱們有一個監控器類,用來監控CPU的溫度,當溫度達到預警的範圍時,監控器有一個報警的方法,方法裏面經過短信提醒器,以發送短信的方式通知維護人員。因而就出現了下面這樣一段最爲常見的代碼:框架

   1:  public class Monitor
   2:  {
   3:         public void Alarm()
   4:         {
   5:                 SMSNotify notify = new SMSNotify();
   6:                 notify.Send();
   7:          }
   8:  }

在Monitor類中,直接引用到了一個短信提醒器的類,這是最爲不靈活和最不易於擴展的一種方式。或許咱們想到了面向接口編程,利用多態的好處,能夠提供靈活的不一樣子類的實現,增長代碼擴展性等等。可是說到底,接口必定是須要實現的,也就是以下語句早晚要執行:函數

   1:  public void Alarm()
   2:  {
   3:         INotify notify = new SMSNotify();
   4:         notify.Send();
   5:  }

這樣看來,在實現INotify這個接口的時候,仍然須要具體的類來實現,而這樣的代碼在程序編譯的時候就已經固定下來,若是之後須要使用新的提醒器,仍舊須要修改源代碼並從新編譯。而且在咱們的Monitor類中,明顯依賴SMSNotify類,兩者之間的耦合度很是緊密。所以Ioc(控制反轉)模式被提出用來解決這種問題,也即把接口的具體實現延緩到運行時,接口的實現類是在運行時被裝載的。這樣,就算有了新的實現類,也不須要更改調用者的代碼(能夠在Unity中使用配置文件的方式實現)。這種Ioc模式能夠被形象的比喻爲:接口就像一個空殼,而在具體實現時,向這個空殼注入內容,而讓它成爲一個真正的實體。這種模式也被形象的稱爲:依賴注入。經過使用Unity,咱們能構建鬆耦合的軟件,而且對象之間相互關聯的細節,咱們也沒必要關心,能夠交由依賴注入容器全權負責。編碼

前面也提到了依賴注入經常使用的三種形式:構造器注入、屬性注入和方法調用注入,咱們能夠經過例子來實現這三種形式的注入。仍是以上面的場景爲例:spa

 

1.Constructor Injectioncode

IMonitor接口定義:對象

   1:  public interface IMonitor
   2:  {
   3:      void Alarm();
   4:  }

Monitor類:接口

   1:  public class Monitor : IMonitor
   2:  {
   3:      private INotify notify;
   4:  
   5:      public Monitor(INotify n)
   6:      {
   7:          notify = n;
   8:      }
   9:  
  10:      public void Alarm()
  11:      {
  12:          notify.Send();
  13:      }
  14:  }

INotify接口定義:開發

   1:  public interface INotify
   2:  {
   3:      void Send();
   4:  }

EmailNotify類:文檔

   1:  public class EmailNotify : INotify
   2:  {
   3:      public void Send()
   4:      {
   5:          Console.WriteLine("Send Email Notify...");
   6:      }
   7:  }

SMSNotify類:

   1:  public class SMSNotify : INotify
   2:  {
   3:      public void Send()
   4:      {
   5:          Console.WriteLine("Send SMS Notify...");
   6:      }
   7:  }

能夠看到,在Monitor類的構造函數裏面,傳入的參數是一個INotify接口類型,Alarm方法,調用了實現類的Send方法,但具體調用哪個實現類的Send方法,只有在注入實體後才知道。Unity容器中,一般使用RegisterType和Resolve方法來分別註冊和獲取實例,而且這兩個方法有不少泛型和非泛型的重載,具體的類型和參數,能夠參考Unity的官方幫助文檔。

如今咱們向Monitor的構造函數注入實現INotify接口的實例:

   1:  static void Main(string[] args)
   2:  {
   3:      IUnityContainer container = new UnityContainer();
   4:      container.RegisterType<IMonitor, Monitor>().RegisterType<INotify, SMSNotify>();
   5:  
   6:      IMonitor monitor = container.Resolve<IMonitor>();
   7:      monitor.Alarm();
   8:  
   9:      Console.ReadLine();
  10:  }

代碼中咱們注入的INotify實例是SMSNotify類的實例,而後調用monitor.Alrarm(),裏面會調用notify.Send().
上面是針對單個構造函數的狀況,若是有多個構造函數,須要指明哪一個構造函數是須要被注入的,也即須要在指定被注入的構造函數加上attribute:InjectionConstructor

   1:  public Monitor(INotify n, string name)
   2:  {
   3:      notify = n;
   4:  }
   5:  
   6:  [InjectionConstructor]
   7:  public Monitor(INotify n)
   8:  {
   9:      notify = n;
  10:  }

運行後可獲得同樣的結果.

2.Property Injection

經過屬性注入,咱們須要加上attribute: Dependency,使得Unity容器在獲取類對象實例時,自動實例化該屬性所依賴的對象,並注入到屬性中。

修改Monitor類,實現下面的代碼:

   1:  public class Monitor : IMonitor
   2:  {
   3:      [Dependency]
   4:      public INotify Notify { get; set; }
   5:  
   6:      public void Alarm()
   7:      {
   8:          Notify.Send();
   9:      }
  10:  }

再在Main函數裏面,修改原有的代碼,此次咱們讓容器注入EmailNotify實例:

   1:  container.RegisterType<INotify, EmailNotify>();

 還有一個比較方便的地方,能夠爲Dependency特性指定名稱,這樣,在注入時,會將RegisterType所指定的對應名稱的實體進行注入,例如:

   1:      public class Monitor : IMonitor
   2:      {
   3:          [Dependency("SMS")]
   4:          public INotify Notify { get; set; }
   5:  
   6:          public void Alarm()
   7:          {
   8:              Notify.Send();
   9:          }
  10:      }

修改Main函數,在RegisterType函數中指定注入名稱:

   1:              container.RegisterType<INotify, EmailNotify>("Email");
   2:              container.RegisterType<INotify, SMSNotify>("SMS");
 

3.Method Call Injection

Method Call Injection注入的時機和Constructor Injection有必定的區別,構造函數注入,是在容器建立實例的時候,而方法調用注入,是在方法被調用的時候。實現方法調用注入,須要在指定注入的方法前加上attribute: InjectionMethod

修改Monitor類的代碼以下:

   1:      public class Monitor : IMonitor
   2:      {
   3:          private INotify notify;
   4:  
   5:          [InjectionMethod]
   6:          public void GetNotify(INotify n)
   7:          {
   8:              notify = n;
   9:          }
  10:  
  11:          public void Alarm()
  12:          {
  13:              notify.Send();
  14:          }
  15:      }

在程序運行時,容器會自動實例化GetNotify方法所依賴的對象,並自動調用該方法,將其注入到方法中。

Main函數以下:

   1:          static void Main(string[] args)
   2:          {
   3:              IUnityContainer container = new UnityContainer();
   4:              container.RegisterType<IMonitor, Monitor>();
   5:              container.RegisterType<INotify, EmailNotify>();
   6:  
   7:              IMonitor monitor = container.Resolve<IMonitor>();
   8:              monitor.Alarm();
   9:  
  10:              Console.ReadLine();
  11:          }
摘自(http://www.lywill.com/archives/kf/2013/Microsoft-Practices-UnityRuMen/)
相關文章
相關標籤/搜索