Microsoft.Practices.Unity入門

來源:互聯網
上載者:User

標籤:http   使用   os   io   strong   檔案   ar   問題   

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,我們能構建松耦合的軟體,並且對象之間相互關聯的細節,我們也不必關心,可以交由依賴注入容器全權負責。

前面也提到了依賴注入常用的三種形式:構造器注入、屬性注入和方法調用注入,我們可以通過例子來實現這三種形式的注入。還是以上面的情境為例:

 

1.Constructor Injection

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/)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.