標籤: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/)