什么是IoC
IoC是Inversion of Control的縮寫,翻譯過來為“控制反轉”。簡單來說,就是將對象的依賴關系交由第三方來控制。在理解這句話之前,我們先來回顧一下IoC的演化。
Ioc前世今生
傳統的new class的方式
我們寫了一個ChineseSpeaker的類,他有一個SayHello的方法並調用輸出控制台:
class Program { static void Main(string[] args) { ChineseSpeaker chineseSpeaker= new ChineseSpeaker(); chineseSpeaker.SayHello(); } } public class ChineseSpeaker { public void SayHello() { Console.WriteLine("你好!!!"); } }
上面看起來沒有任何問題,一切都很好,但是有一天英國演講者打招呼的話,我們就需要新建了一個BritishSpeaker類:
class Program { static void Main(string[] args) { //ChineseSpeaker chineseSpeaker = new ChineseSpeaker(); //chineseSpeaker.SayHello(); BritishSpeaker britishSpeaker = new BritishSpeaker(); britishSpeaker.SayHello(); } } public class BritishSpeaker { public void SayHello() { Console.WriteLine("Hello!!!"); } } //ChineseSpeaker 同上面的代碼一樣
當出現“日本人”、“印度人”時,我們不得不修改和重新編譯代碼。當程序代碼和邏輯不復雜的時候問題不大,但當程序變大的時候程序猿就苦逼了。
Interface方式
因此,我們把代碼改成:
public interface ISpeak { void SayHello(); } public class BritishSpeaker : ISpeak { public void SayHello() { Console.WriteLine("Hello!!!"); } } public class ChineseSpeaker : ISpeak { public void SayHello() { Console.WriteLine("你好!!!"); } }
class Program { static void Main(string[] args) { //ChineseSpeaker chineseSpeaker = new ChineseSpeaker(); //chineseSpeaker.SayHello(); //BritishSpeaker britishSpeaker = new BritishSpeaker(); //britishSpeaker.SayHello(); ISpeak speak; if (args.Length > 0 && args[0] == "Chinese") { speak = new ChineseSpeaker(); } else { speak = new BritishSpeaker(); } speak.SayHello(); } }
這時候我們不知不覺的用到了面向對象六大原則中的依賴倒轉原則(DIP),高層模塊不依賴於低層模塊的實現,而低層模塊依賴於高層模塊定義的接口。 好,讓我們回到IoC,比較上面的兩種寫法:
- 傳統的寫法類在定義的瞬間就已經決定具體的類型,他的流程是從上到下的
- 使用interface的寫法是在實例化時才決定類的具體類型,也就是用到的時候才會new(),他的流程是new后面來控制的
這時候我們再來看IoC的意思是控制反轉,就能大概理解了。傳統的寫法流程屬於從上到下,而interface寫法則是由new()其他的類來決定類的實現,因此控制的流程反轉了。
DI是什么
利用interface的方式,可以讓類在使用的時候再決定由哪個具體類來實現。那該如何實現這種方式呢?這時就有一個新的名稱出現了,就是Dependency Injection(依賴注入),簡稱DI。DI有三種方式,分別是構造函數注入、屬性注入、接口注入
構造函數注入
public class Printer { private ISpeak _speak; public Printer(ISpeak speak)//構造函數注入 { _speak = speak; } } class Program { static void Main(string[] args) { //ChineseSpeaker chineseSpeaker = new ChineseSpeaker(); //chineseSpeaker.SayHello(); //BritishSpeaker britishSpeaker = new BritishSpeaker(); //britishSpeaker.SayHello(); //ISpeak speak; //if (args.Length > 0 && args[0] == "Chinese") //{ // speak = new ChineseSpeaker(); //} //else //{ // speak = new BritishSpeaker(); //} //speak.SayHello(); Printer print; if (args.Length > 0 && args[0] == "Chinese") { print = new Printer(new ChineseSpeaker()); } else { print = new Printer(new BritishSpeaker()); } } }
屬性注入
public class Printer { public ISpeak Speaker { get; set; } } class Program { static void Main(string[] args) { //ChineseSpeaker chineseSpeaker = new ChineseSpeaker(); //chineseSpeaker.SayHello(); //BritishSpeaker britishSpeaker = new BritishSpeaker(); //britishSpeaker.SayHello(); //ISpeak speak; //if (args.Length > 0 && args[0] == "Chinese") //{ // speak = new ChineseSpeaker(); //} //else //{ // speak = new BritishSpeaker(); //} //speak.SayHello(); Printer print = new Printer(); if (args.Length > 0 && args[0] == "Chinese") { print.Speaker = new ChineseSpeaker(); } else { print.Speaker = new BritishSpeaker(); } } }
接口注入
//接口注入 public interface IPrint { void SetSpeaker(ISpeak speak); } public class Printer : IPrint { private ISpeak _speak; public void SetSpeaker(ISpeak speak) { _speak = speak; } } class Program { static void Main(string[] args) { //ChineseSpeaker chineseSpeaker = new ChineseSpeaker(); //chineseSpeaker.SayHello(); //BritishSpeaker britishSpeaker = new BritishSpeaker(); //britishSpeaker.SayHello(); ISpeak speak; if (args.Length > 0 && args[0] == "Chinese") { speak = new ChineseSpeaker(); } else { speak = new BritishSpeaker(); } Printer printer = new Printer(); printer.SetSpeaker(speak); } }
IoC與DI的關系
我的理解是IoC是一種理念,DI則是它的具體實現方式
IoC Container
IoC Container幫我們在項目運行時動態的創建實例,它主要功能如下:
- 動態創建、注入依賴對象
- 管理對象生命周期
- 映射依賴關系
IoC Container技術實現的原理就是“反射(Reflection)”。利用反射動態的創建對象,把依賴關系注入到指定對象中。一般常用的注入方式是構造函數注入和屬性注入
Service Locator模式
服務定位模式也是IoC理念的一種實現。實現原理:通過ServiceLocator類提供實現IServiceLocator接口的單例,並負責管理已注冊實例的創建和訪問。通常結合工廠模式來結合使用。
Service Locator與IoC Container都是IoC的具體實現方式。不同的是Service Locator沒有提供管理對象生命周期的功能
.NET 平台下的IoC Container框架
Ninject: http://www.ninject.org/
Castle Windsor: http://www.castleproject.org/container/index.html
Autofac: http://code.google.com/p/autofac/
StructureMap: http://docs.structuremap.net/
Unity: http://unity.codeplex.com/
Spring.NET: http://www.springframework.net/
結束語
我在學習IoC過程中,學以致用,自己模仿Nject實現了一個IoC Container框架,可以用FluentAPI和xml配置依賴關系,希望對大家有幫助。項目地址:https://github.com/Khadron/Peace