1、引言設計模式
IOC-Invertion of Control,即控制反轉,是一種程序設計思想,世上本沒有路,走的人多了便有了路,本文將一步步帶你瞭解IOC設計思想的演進之路。架構
在學習IOC以前咱們先初步瞭解幾個概念app
依賴(Dependency):就是有聯繫,表示一個類依賴於另外一個類框架
依賴倒置原則(DIP):設計模式六大原則之一,是一種軟件架構設計原則ide
控制反轉(IOC):一種軟件設計原則,上層對下層的依賴(即底層模塊的得到)交給第三方函數
依賴注入(DI):實現IOC的一種方式、手段學習
IOC容器:依賴注入的框架,用來映射依賴,管理對象建立和生存週期spa
2、依賴架構設計
依賴就是有聯繫,有地方使用它就是有依賴它,下面看一個簡單的示例設計
class BMW { public string Show() { return "寶馬"; } } class ChinesePeople { private BMW bmw = new BMW(); public void Run() { Console.WriteLine($"今天開{bmw.Show()}上班"); } } class Program { static void Main(string[] args) { ChinesePeople people = new ChinesePeople(); BMW bmw = new BMW(); people.Run(); Console.Read(); } }
上面中國人開着寶馬去上班,客戶端有使用中國人、寶馬汽車兩個對象,中國人中有使用對象寶馬汽車,咱們能夠從中找到三個依賴關係:
客戶端依賴對象ChinesePeople;
客戶端依賴對象BMW;
ChinesePeople依賴對象BMW;
3、依賴倒置原則
過些日子來了新需求,中國人不只要開寶馬去上班,還要開奔馳去上班,若是按照上面直接依賴關係的方式去作,咱們就須要修改ChinesePeople類,讓它實現一個參數爲寶馬的重載方法Run(),顯然這樣不是好的設計,咱們總不能每次新增一種汽車(即修改下層模塊)都要去修改ChinesePeople類吧(相對於汽車爲上層模塊),太麻煩了。。。
先簡單分析一下,耦合關係就是依賴關係,若是依賴關係很重,牽一髮而動全身,將很難維護擴展,耦合關係越少,系統會越穩定,所以要較少依賴
定義:A.高層模塊不該依賴於底層模塊,二者應該依賴於抽象
B.抽象不該該依賴於細節,細節應該依賴於抽象
在這個圖中,咱們發現高層模塊定義接口,將不直接依賴於下層模塊,下層模塊負責實現高層模塊定義的接口,下面看代碼demo:
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "寶馬"; } } class BenZ : ICar { public string Show() { return "奔馳"; } } interface IPeople { void Run(ICar bmw); } class ChinesePeople :IPeople { public void Run(ICar bmw) { Console.WriteLine($"今天開{bmw.Show()}上班"); } } class Program { static void Main(string[] args) { ICar carBMW = new BMW(); ICar carBenZ = new BenZ(); IPeople people = new ChinesePeople(); people.Run(carBMW); people.Run(carBenZ); Console.Read(); } }
分析:上面代碼中,ChinesePeople類再也不依賴於具體的汽車,而是依賴於汽車的抽象,這樣使得無論換什麼樣的汽車品牌,中國人都是能夠開着去上班的,並且不須要修改ChinesePeople類。想一下,這樣是否是挺好的,咱們能夠得出:上層再也不依賴細節,相比面向實現,面向接口較好,由於抽象相比細節要更穩定。
4、控制反轉
上面示例中,咱們實現了具體的人和具體的汽車的隔離,具體人只和汽車的接口有關。可是Program中main方法裏的具體對象寫死了,控制權變小,當我要修改美國人開着福特去上班時,就不得不要去修改代碼,那怎麼把控制權轉移呢?
下面看一個簡單的示例:
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "寶馬"; } } interface IPeople { void Run(ICar bmw); } class ChinesePeople :IPeople { public void Run(ICar bmw) { Console.WriteLine($"今天開{bmw.Show()}上班"); } } class Program { static void Main(string[] args) { string people = ConfigurationManager.AppSettings["people"]; string car = ConfigurationManager.AppSettings["car"]; Assembly assemblypeople = Assembly.Load(people.Split(',')[1]); Assembly assemblycar = Assembly.Load(car.Split(',')[1]); Type typepeople = assemblypeople.GetType(people.Split(',')[0]); Type typecar = assemblypeople.GetType(car.Split(',')[0]); IPeople ipeople= (IPeople)Activator.CreateInstance(typepeople); ICar icar = (ICar)Activator.CreateInstance(typecar); ipeople.Run(icar); Console.Read(); } } <?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> <add key="people" value="MyIOC_IOC.ChinesePeople,MyIOC_IOC"/> <add key="car" value="MyIOC_IOC.BMW,MyIOC_IOC"/> </appSettings> </configuration>
上面代碼中,咱們使用反射+配置文件的方式,將對象建立的控制權轉移到了配置文件,這就是所謂的控制反轉
分析,控制反轉是將對象建立的控制權交給了第三方,能夠是IOC容器,它就至關於工廠,咱們要什麼對象,工廠給咱們什麼對象,這樣依賴關係就變了,它們(人和車)都依賴於IOC容器,經過IOC容器創建它們之間的依賴關係。(依賴對象再也不被依賴模塊的類中直接經過new來獲取)
5、依賴注入
上面說到的控制反轉,咱們瞭解到是將控制權轉移,這是咱們的目的,配置文件+反射是是一種實現,而依賴注入則提供的是一種思想,或者說是實現IOC的手段。
依賴注入是將對象的建立和綁定轉移到被依賴對象的外部來實現。在依賴關係中ChinesePeople類所依賴的對象BMW類的建立和綁定是在ChinesePeople類內部執行的,顯然這種方法是不可取的,那咱們怎麼BMW類的引用傳遞給ChinesePeople類呢?
方法一 構造函數注入
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "寶馬"; } } class ChinesePeopleContructor { private ICar _car; public ChinesePeopleContructor(ICar bmw) { _car = bmw; } public void Run() { Console.WriteLine($"今天開{_car.Show()}上班"); } } static void Main(string[] args) { ICar car = new BMW(); ChinesePeopleContructor people = new ChinesePeopleContructor(car); people.Run(); Console.Read(); }
分析,BMW類對象的建立和綁定轉移到ChinesePeople類的外部來實現,解除了兩個對象之間的耦合,當須要開奔馳去上班的時候,只須要定義一個奔馳類,外部從新綁定依賴,不須要修改ChinesePeople類的內部,便可是先中國人開奔馳去上班的需求
方法二 屬性注入
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "寶馬"; } } class ChinesePeopleProperty { private ICar _ICar; public ICar IC { get { return _ICar; } set { _ICar = value; } } public void Run() { Console.WriteLine($"今天開{_ICar.Show()}上班"); } } static void Main(string[] args) { ICar car = new BMW(); ChinesePeopleProperty people = new ChinesePeopleProperty(); people.IC = car; people.Run(); Console.Read(); }
分析,屬性注入是經過給屬性賦值,從而傳遞依賴
方法三 接口注入
interface ICar { string Show(); } class BMW:ICar { public string Show() { return "寶馬"; } } interface IDependent { void SetDependent(ICar icar); } class ChinesePeopleInterface : IDependent { private ICar _ICar; public void SetDependent(ICar icar) { _ICar = icar; } public void Run() { Console.WriteLine($"今天開{_ICar.Show()}上班"); } } static void Main(string[] args) { ICar car = new BMW(); ChinesePeopleInterface people = new ChinesePeopleInterface(); people.SetDependent(car); people.Run(); Console.Read(); }
分析,接口依賴是定義一個設置依賴的方法,而後被依賴類繼承並實現這個接口
6、IOC容器
IOC容器是一個DI框架,主要功能有一下幾點
1.動態建立、注入依賴對象;
2.管理對象生命週期
2.映射依賴關係
常見的IOC容器:Spring.NET,Castle Windsor, Ninject,Autofac,Unity等等。。。
ioc容器提供了不少豐富的API,因爲時間和篇幅等關係,我會在下篇博客中和您一塊兒學習IOC容器之一Unity,敬請期待,未完待續。。。
不努力一把,坐井觀天,將永遠不知道本身和別人的差距有多大,身爲菜鳥的我相信,天道酬勤,大道至簡,最好的成功之道即是堅持、學習、總結。
本文版權歸做者和博客園共有,歡迎轉載,轉載請註明出處。感謝您的閱讀。