最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

深入理解DIP、IoC、DI以及IoC容器

2021-01-05 10:52 作者:自學(xué)Python的小姐姐呀  | 我要投稿

對于大部分小菜來說,當(dāng)聽到大牛們高談DIP、IoC、DI以及IoC容器等名詞時,有沒有瞬間石化的感覺?其實,這些“高大上”的名詞,理解起來也并不是那么的難,關(guān)鍵在于入門。只要我們?nèi)腴T了,然后循序漸進(jìn),假以時日,自然水到渠成。

好吧,我們先初略了解一下這些概念。

依賴倒置原則(DIP):一種軟件架構(gòu)設(shè)計的原則(抽象概念)。

控制反轉(zhuǎn)(IoC):一種反轉(zhuǎn)流、依賴和接口的方式(DIP的具體實現(xiàn)方式)。

依賴注入(DI):IoC的一種實現(xiàn)方式,用來反轉(zhuǎn)依賴(IoC的具體實現(xiàn)方式)。

IoC容器:依賴注入的框架,用來映射依賴,管理對象創(chuàng)建和生存周期(DI框架)。

哦!也許你正為這些陌生的概念而傷透腦筋。不過沒關(guān)系,接下來我將為你一一道破這其中的玄機(jī)。


依賴倒置原則(DIP)

在講概念之前,我們先看生活中的一個例子。

圖1??ATM與銀行卡


相信大部分取過錢的朋友都深有感觸,只要有一張卡,隨便到哪一家銀行的ATM都能取錢。在這個場景中,ATM相當(dāng)于高層模塊,而銀行卡相當(dāng)于低層模塊。ATM定義了一個插口(接口),供所有的銀行卡插入使用。也就是說,ATM不依賴于具體的哪種銀行卡。它只需定義好銀行卡的規(guī)格參數(shù)(接口),所有實現(xiàn)了這種規(guī)格參數(shù)的銀行卡都能在ATM上使用?,F(xiàn)實生活如此,軟件開發(fā)更是如此。依賴倒置原則,它轉(zhuǎn)換了依賴,高層模塊不依賴于低層模塊的實現(xiàn),而低層模塊依賴于高層模塊定義的接口。通俗的講,就是高層模塊定義接口,低層模塊負(fù)責(zé)實現(xiàn)。

Bob Martins對DIP的定義:
高層模塊不應(yīng)依賴于低層模塊,兩者應(yīng)該依賴于抽象。
抽象不不應(yīng)該依賴于實現(xiàn),實現(xiàn)應(yīng)該依賴于抽象。

?

如果生活中的實例不足以說明依賴倒置原則的重要性,那下面我們將通過軟件開發(fā)的場景來理解為什么要使用依賴倒置原則。


場景一?依賴無倒置(低層模塊定義接口,高層模塊負(fù)責(zé)實現(xiàn))

從上圖中,我們發(fā)現(xiàn)高層模塊的類依賴于低層模塊的接口。因此,低層模塊需要考慮到所有的接口。如果有新的低層模塊類出現(xiàn)時,高層模塊需要修改代碼,來實現(xiàn)新的低層模塊的接口。這樣,就破壞了開放封閉原則。


場景二 依賴倒置(高層模塊定義接口,低層模塊負(fù)責(zé)實現(xiàn))

在這個圖中,我們發(fā)現(xiàn)高層模塊定義了接口,將不再直接依賴于低層模塊,低層模塊負(fù)責(zé)實現(xiàn)高層模塊定義的接口。這樣,當(dāng)有新的低層模塊實現(xiàn)時,不需要修改高層模塊的代碼。

由此,我們可以總結(jié)出使用DIP的優(yōu)點:

系統(tǒng)更柔韌:可以修改一部分代碼而不影響其他模塊。

系統(tǒng)更健壯:可以修改一部分代碼而不會讓系統(tǒng)崩潰。

系統(tǒng)更高效:組件松耦合,且可復(fù)用,提高開發(fā)效率。


控制反轉(zhuǎn)(IoC)

DIP是一種?軟件設(shè)計原則,它僅僅告訴你兩個模塊之間應(yīng)該如何依賴,但是它并沒有告訴如何做。IoC則是一種?軟件設(shè)計模式,它告訴你應(yīng)該如何做,來解除相互依賴模塊的耦合。控制反轉(zhuǎn)(IoC),它為相互依賴的組件提供抽象,將依賴(低層模塊)對象的獲得交給第三方(系統(tǒng))來控制即依賴對象不在被依賴模塊的類中直接通過new來獲取。在圖1的例子我們可以看到,ATM它自身并沒有插入具體的銀行卡(工行卡、農(nóng)行卡等等),而是將插卡工作交給人來控制,即我們來決定將插入什么樣的銀行卡來取錢。同樣我們也通過軟件開發(fā)過程中場景來加深理解。

軟件設(shè)計原則:原則為我們提供指南,它告訴我們什么是對的,什么是錯的。它不會告訴我們?nèi)绾谓鉀Q問題。它僅僅給出一些準(zhǔn)則,以便我們可以設(shè)計好的軟件,避免不良的設(shè)計。一些常見的原則,比如DRY、OCP、DIP等。
軟件設(shè)計模式:模式是在軟件開發(fā)過程中總結(jié)得出的一些可重用的解決方案,它能解決一些實際的問題。一些常見的模式,比如工廠模式、單例模式等等。

做過電商網(wǎng)站的朋友都會面臨這樣一個問題:訂單入庫。假設(shè)系統(tǒng)設(shè)計初期,用的是SQL Server數(shù)據(jù)庫。通常我們會定義一個SqlServerDal類,用于數(shù)據(jù)庫的讀寫。

然后我們定義一個Order類,負(fù)責(zé)訂單的邏輯處理。由于訂單要入庫,需要依賴于數(shù)據(jù)庫的操作。因此在Order類中,我們需要定義SqlServerDal類的變量并初始化。

最后,我們寫一個控制臺程序來檢驗成果。

?輸出結(jié)果:

?OK,結(jié)果看起來挺不錯的!正當(dāng)你沾沾自喜的時候,這時BOSS過來了?!靶?,剛客戶那邊打電話過來說數(shù)據(jù)庫要改成Access”,“對你來說,應(yīng)當(dāng)小CASE啦!”BOSS又補充道。帶著自豪而又糾結(jié)的情緒,我們思考著修改代碼的思路。

?由于換成了Access數(shù)據(jù)庫,SqlServerDal類肯定用不了了。因此,我們需要新定義一個AccessDal類,負(fù)責(zé)Access數(shù)據(jù)庫的操作。

?然后,再看Order類中的代碼。由于,Order類中直接引用了SqlServerDal類的對象。所以還需要修改引用,換成AccessDal對象。

輸出結(jié)果:

費了九牛二虎之力,程序終于跑起來了!試想一下,如果下次客戶要換成MySql數(shù)據(jù)庫,那我們是不是還得重新修改代碼?

顯然,這不是一個良好的設(shè)計,組件之間高度耦合,可擴(kuò)展性較差,它違背了DIP原則。高層模塊Order類不應(yīng)該依賴于低層模塊SqlServerDal,AccessDal,兩者應(yīng)該依賴于抽象。那么我們是否可以通過IoC來優(yōu)化代碼呢?答案是肯定的。IoC有2種常見的實現(xiàn)方式:依賴注入和服務(wù)定位。其中,依賴注入使用最為廣泛。下面我們將深入理解依賴注入(DI),并學(xué)會使用。


依賴注入(DI)

控制反轉(zhuǎn)(IoC)一種重要的方式,就是將依賴對象的創(chuàng)建和綁定轉(zhuǎn)移到被依賴對象類的外部來實現(xiàn)。在上述的實例中,Order類所依賴的對象SqlServerDal的創(chuàng)建和綁定是在Order類內(nèi)部進(jìn)行的。事實證明,這種方法并不可取。既然,不能在Order類內(nèi)部直接綁定依賴關(guān)系,那么如何將SqlServerDal對象的引用傳遞給Order類使用呢?

依賴注入(DI),它提供一種機(jī)制,將需要依賴(低層模塊)對象的引用傳遞給被依賴(高層模塊)對象。通過DI,我們可以在Order類的外部將SqlServerDal對象的引用傳遞給Order類對象。那么具體是如何實現(xiàn)呢?


方法一 構(gòu)造函數(shù)注入

構(gòu)造函數(shù)函數(shù)注入,毫無疑問通過構(gòu)造函數(shù)傳遞依賴。因此,構(gòu)造函數(shù)的參數(shù)必然用來接收一個依賴對象。那么參數(shù)的類型是什么呢?具體依賴對象的類型?還是一個抽象類型?根據(jù)DIP原則,我們知道高層模塊不應(yīng)該依賴于低層模塊,兩者應(yīng)該依賴于抽象。那么構(gòu)造函數(shù)的參數(shù)應(yīng)該是一個抽象類型。我們再回到上面那個問題,如何將SqlServerDal對象的引用傳遞給Order類使用呢

首選,我們需要定義SqlServerDal的抽象類型IDataAccess,并在IDataAccess接口中聲明一個Add方法。

?然后在SqlServerDal類中,實現(xiàn)IDataAccess接口。

接下來,我們還需要修改Order類。

?OK,我們再來編寫一個控制臺程序。

?輸出結(jié)果:

從上面我們可以看出,我們將依賴對象SqlServerDal對象的創(chuàng)建和綁定轉(zhuǎn)移到Order類外部來實現(xiàn),這樣就解除了SqlServerDal和Order類的耦合關(guān)系。當(dāng)我們數(shù)據(jù)庫換成Access數(shù)據(jù)庫時,只需定義一個AccessDal類,然后外部重新綁定依賴,不需要修改Order類內(nèi)部代碼,則可實現(xiàn)Access數(shù)據(jù)庫的操作。

定義AccessDal類:

然后在控制臺程序中重新綁定依賴關(guān)系:

輸出結(jié)果:

顯然,我們不需要修改Order類的代碼,就完成了Access數(shù)據(jù)庫的移植,這無疑體現(xiàn)了IoC的精妙。


方法二 屬性注入

顧名思義,屬性注入是通過屬性來傳遞依賴。因此,我們首先需要在依賴類Order中定義一個屬性:

?然后在控制臺程序中,給屬性賦值,從而傳遞依賴:

我們可以得到上述同樣的結(jié)果。


?方法三 接口注入

相比構(gòu)造函數(shù)注入和屬性注入,接口注入顯得有些復(fù)雜,使用也不常見。具體思路是先定義一個接口,包含一個設(shè)置依賴的方法。然后依賴類,繼承并實現(xiàn)這個接口。

首先定義一個接口:?

依賴類實現(xiàn)這個接口:

控制臺程序通過SetDependence方法傳遞依賴:

我們同樣能得到上述的輸出結(jié)果。


IoC容器

前面所有的例子中,我們都是通過手動的方式來創(chuàng)建依賴對象,并將引用傳遞給被依賴模塊。比如:

SqlServerDal dal =?new?SqlServerDal();//在外部創(chuàng)建依賴對象

Order order =?new?Order(dal);//通過構(gòu)造函數(shù)注入依賴


對于大型項目來說,相互依賴的組件比較多。如果還用手動的方式,自己來創(chuàng)建和注入依賴的話,顯然效率很低,而且往往還會出現(xiàn)不可控的場面。正因如此,IoC容器誕生了。IoC容器實際上是一個DI框架,它能簡化我們的工作量。它包含以下幾個功能:

  • 動態(tài)創(chuàng)建、注入依賴對象。

  • 管理對象生命周期。

  • 映射依賴關(guān)系。

目前,比較流行的Ioc容器有以下幾種:

1.?Ninject

2.?Castle Windsor

3.?Autofac

4.?StructureMap

5.?Unity

6.?Spring.NET

7.?LightInject

?以Ninject為例,我們同樣來實現(xiàn)?[方法一 構(gòu)造函數(shù)注入]?的功能。


首先在項目添加Ninject程序集,同時使用using指令引入。?

using?Ninject;


然后,Ioc容器注冊綁定依賴:

StandardKernel kernel =?new?StandardKernel();

kernel.Bind<IDataAccess>().To<SqlServerDal>();//注冊依賴


?接下來,我們獲取需要的Order對象(注入了依賴對象):

Order order = kernel.Get<Order>();


?下面,我們寫一個完整的控制臺程序

輸出結(jié)果:

使用IoC容器,我們同樣實現(xiàn)了該功能。


總結(jié)

DIP是軟件設(shè)計的一種思想,IoC則是基于DIP衍生出的一種軟件設(shè)計模式。DI是IoC的具體實現(xiàn)方式之一,使用最為廣泛。IoC容器是DI構(gòu)造函注入的框架,它管理著依賴項的生命周期以及映射關(guān)系。


深入理解DIP、IoC、DI以及IoC容器的評論 (共 條)

分享到微博請遵守國家法律
常熟市| 齐齐哈尔市| 三亚市| 昂仁县| 施甸县| 出国| 遵义县| 孝昌县| 丹东市| 体育| 革吉县| 襄汾县| 静宁县| 阳春市| 穆棱市| 泸水县| 虞城县| 密云县| 徐闻县| 石景山区| 商城县| 房产| 漳平市| 凤翔县| 肇东市| 罗江县| 金平| 岳西县| 奉节县| 育儿| 香港 | 叙永县| 北海市| 文水县| 封开县| 平定县| 福安市| 菏泽市| 会同县| 隆昌县| 西安市|