日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

不要叫我,我会叫你

發(fā)布時(shí)間:2023/12/4 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 不要叫我,我会叫你 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前看過前輩Artech關(guān)于控制反轉(zhuǎn)的一篇文章,文章通俗易懂且言語精煉,寫技術(shù)文章既是積累也是分享,既然是分享那么必須讓讀者能夠明白到底講解的什么,所以在這里我也挑戰(zhàn)下自己,看看能不能將概念通過簡(jiǎn)潔代碼和語言的形式充分闡述清楚,若有錯(cuò)誤之處,還望指正。

什么是控制反轉(zhuǎn)

控制反轉(zhuǎn)的英文名為Inversion Of Control,我們簡(jiǎn)稱為IOC,控制反轉(zhuǎn)是一個(gè)原則而不是一個(gè)設(shè)計(jì)模式,它是反轉(zhuǎn)程序的控制流,這個(gè)術(shù)語在Steapano Mazzocchi的Apache軟件基金會(huì)項(xiàng)目Avalon中被推廣,然后在2004年由Robert C. Martin和Martin Fowler進(jìn)一步推廣。

正如Martin Fowler所說:控制反轉(zhuǎn)是框架的共同特征,因此說這些輕量級(jí)容器之所以特別是因?yàn)樗鼈兪褂每刂品崔D(zhuǎn),就好像在說我的車很特別,因?yàn)樗鼛в休喿右粯印K旧鲜强蚣艿亩x特征,控制反轉(zhuǎn)用于增加程序的模塊化并使其可擴(kuò)展。

那么問題來了,真正反轉(zhuǎn)體現(xiàn)在哪里呢?在早期計(jì)算機(jī)軟件,命令行用于通用程序,因此用戶界面由應(yīng)用程序本身控制,在程序中,我們可以通過將響應(yīng)輸入命令行來直接控制程序的流程,但是在GUI程序中,我們基本上是將控件移交給了窗口系統(tǒng)(UI框架),然后由窗口系統(tǒng)決定下一步要做什么,此時(shí)程序的主控件從我們移到了UI框架。

控制反轉(zhuǎn)是庫(kù)和框架之間的區(qū)別,使用庫(kù)時(shí),庫(kù)本質(zhì)上是調(diào)用特定的函數(shù)和方法來執(zhí)行計(jì)算和操作,每個(gè)調(diào)用都會(huì)完成一些工作,并將控制權(quán)返回到客戶端,而框架會(huì)為我們完成一些工作,我們只需要向框架不同位置注冊(cè)我們所編寫的代碼,然后,框架將在需要時(shí)調(diào)用我們編寫的代碼。

用更加通俗易懂的話理解則是:不要叫我,我會(huì)叫你或者不要給我們打電話,我們會(huì)通知你(好萊塢法則)。有了對(duì)概念的初步理解,接下來我們通過代碼的形式來加深對(duì)概念的理解。

我們反觀上述代碼,因?yàn)槠嚨慕M成離不開引擎構(gòu)造,當(dāng)我們調(diào)用汽車對(duì)象實(shí)例時(shí),將主動(dòng)去構(gòu)造引擎對(duì)象實(shí)例,表述上沒有任何問題,但是我們意識(shí)到引擎和汽車緊密結(jié)合在了一起,如果構(gòu)造引擎對(duì)象一旦發(fā)生變化,毫無疑問我們需要修改汽車對(duì)象,也就是說汽車對(duì)象強(qiáng)依賴引擎對(duì)象,現(xiàn)在我們將代碼進(jìn)行如下修改:

在此種情況下,汽車對(duì)象并不知道如何構(gòu)造引擎對(duì)象,當(dāng)調(diào)用汽車時(shí),汽車的調(diào)用者有責(zé)任和義務(wù)將引擎對(duì)象實(shí)例傳遞給汽車,此時(shí)流程控制被反轉(zhuǎn),這種反轉(zhuǎn)類似于基于事件的處理機(jī)制。也就是說流程管理從應(yīng)用程序轉(zhuǎn)移到了框架,經(jīng)過如此修改后,引擎上升到了框架,如黑匣子一般,因?yàn)槲覀儾⒉魂P(guān)心引擎具體如何構(gòu)造。同時(shí)我們也可看出,通過控制反轉(zhuǎn)使程序更加靈活和松散耦合。講完了控制反轉(zhuǎn)的概念和例子,我們似乎還有一個(gè)未進(jìn)行講解,好像我們聽到更多的是依賴注入,那么依賴注入和控制反轉(zhuǎn)有著怎樣的聯(lián)系呢?

依賴注入和控制反轉(zhuǎn)兩個(gè)相關(guān)但概念截然不同,依賴注入的思想就是一個(gè)單獨(dú)對(duì)象,說白了就是編寫類的方式,使得可以在構(gòu)造時(shí)將類或函數(shù)的特定實(shí)例傳遞給它們,依賴注入其實(shí)就意味著控制反轉(zhuǎn),因?yàn)楫?dāng)我們?cè)趯?duì)象上調(diào)用方法時(shí),它們不再定位它們所需的其他對(duì)象。取而代之的是,它們?cè)跇?gòu)造時(shí)就已被賦予了依賴關(guān)系,但我們?nèi)匀槐仨毠芾順?gòu)造,通過使用控件容器的反轉(zhuǎn),我們可以使依賴注入更進(jìn)一步,通過反轉(zhuǎn)控制容器,我們只需預(yù)先注冊(cè)所有可用的類。當(dāng)容器需要構(gòu)造一個(gè)類的實(shí)例時(shí),它可以檢查該類的構(gòu)造函數(shù)需要哪些對(duì)象,然后可以從向其注冊(cè)的類中構(gòu)造適當(dāng)?shù)膶?shí)例,總的來說依賴注入只是實(shí)現(xiàn)控制反轉(zhuǎn)的一種方式而已。

我們拋開依賴注入實(shí)現(xiàn)了控制反轉(zhuǎn),僅僅只討論依賴注入帶來了哪些好處。

既然是面向?qū)ο蟮恼Z言,那么我們是編寫基于面向?qū)ο蟮拇a,那么對(duì)象自然而然就有其生命周期,有的對(duì)象可能我們只需要一個(gè)實(shí)例,有的對(duì)象可能在程序運(yùn)行整個(gè)過程中一直存在也就是全局實(shí)例,而且有的對(duì)象里面存在著對(duì)其他對(duì)象的引用,如此一來會(huì)造成什么問題呢?導(dǎo)致代碼難以理解而且難以更改,尤其是對(duì)于全局實(shí)例而言,全局實(shí)例離散性行為太強(qiáng),分散在整個(gè)項(xiàng)目中的各個(gè)角落,最主要的是我們所編寫的代碼細(xì)節(jié)中也隱藏了對(duì)象之間的交互,有些實(shí)例就包含了對(duì)其他實(shí)例的引用,一旦出現(xiàn)問題,我們唯有通讀每一行代碼。

我們通過引入依賴注入代替全局實(shí)例方式,通過依賴注入常用方式即構(gòu)造函數(shù)注入注入依賴項(xiàng)參數(shù),此舉將提高代碼的可讀性,我們只需快速瀏覽構(gòu)造函數(shù)即可查看對(duì)應(yīng)依賴關(guān)系。通過引入依賴注入我們需要注意的是對(duì)對(duì)應(yīng)類進(jìn)行合理劃分,因?yàn)槊看我胄碌囊蕾図?xiàng)時(shí),可能還是存在類與類之間的依賴,將不同行為劃分到不同組,如此才能減少類與類之間的耦合,使得我們的設(shè)計(jì)更具凝聚力。通過引入依賴注入也使得我們?cè)谶M(jìn)行單元測(cè)試時(shí)更加方便,因?yàn)槲覀兛赏ㄟ^隔離類來直接測(cè)試類實(shí)例。

控制反轉(zhuǎn)代碼說明

接下來我們討論下如何利用程序?qū)崿F(xiàn)控制反轉(zhuǎn),實(shí)現(xiàn)控制反轉(zhuǎn)最常見的兩種方式則是:服務(wù)定位器模式(SL)和依賴注入模式(DI)。接下來我們通過例子利用依賴注入和服務(wù)定位器模式實(shí)現(xiàn)控制反轉(zhuǎn)。我們通過控制臺(tái)實(shí)現(xiàn)獲取圖書館庫(kù)圖書列表,查詢我們想要的圖書,如下我們定義圖書類:

然后接下來我們將控制臺(tái)程序名稱修改為圖書館庫(kù),然后根據(jù)我們輸入的圖書來查詢圖書并打印,偽代碼如下:

如上我們通過bookFinder獲取圖書館圖書列表,然后查詢我們輸入的圖書名稱并打印,我們一眼就能看出這個(gè)bookFinder從哪里來呢?我們可能查找深圳圖書館或者國(guó)家圖書館或者網(wǎng)上遠(yuǎn)程爬取呢?,所以接下來我們需要?jiǎng)?chuàng)建bookFinder的接口實(shí)現(xiàn),如下:

經(jīng)過上述改造后,我們提供了IBookFinder接口以及其實(shí)現(xiàn),但是現(xiàn)在我們正在將其作為一個(gè)框架,需要被其他人可擴(kuò)展和使用,若此時(shí)需要提供給國(guó)家圖書館使用呢?我們可以看到此時(shí)圖書庫(kù)即Library同時(shí)依賴IBookFinder和及其實(shí)現(xiàn),當(dāng)我們作為可擴(kuò)展框架時(shí),最佳效果則是依賴接口而不是依賴具體實(shí)現(xiàn)細(xì)節(jié),那么此時(shí)該實(shí)例我們到底該如何使用呢?答案則是控制反轉(zhuǎn),我們通過依賴注入實(shí)現(xiàn)控制反轉(zhuǎn)。

接下來我們將上述圖書館庫(kù)Library修改為通過構(gòu)造函數(shù)注入IBookFinder接口,此時(shí)庫(kù)將僅僅只依賴于IBookFinder接口,IBookFinder內(nèi)部具體實(shí)現(xiàn)Library并不關(guān)心,然后在控制臺(tái)進(jìn)行如下調(diào)用:

上述我們通過依賴注入使得我們可以進(jìn)行可擴(kuò)展,根據(jù)不同圖書館需要只需提供IBookFinder具體實(shí)現(xiàn)即可,依賴注入并不是實(shí)現(xiàn)控制反轉(zhuǎn)唯一的方式,我們還可以通過服務(wù)定位器來實(shí)現(xiàn),服務(wù)定位器的背后是一個(gè)對(duì)象,該對(duì)象知道如何獲取應(yīng)用程序可能需要的所有服務(wù),也就是說服務(wù)定位器提供我們返回IBookFinder接口的實(shí)現(xiàn),如下:

通過依賴注入和服務(wù)定位器實(shí)現(xiàn)控制反轉(zhuǎn)都分離了相互依賴,只不過依賴注入讓我們通過構(gòu)造函數(shù)一目了然就可查看依賴關(guān)系,而服務(wù)定位器需要顯式請(qǐng)求依賴關(guān)系,本質(zhì)上沒有任何區(qū)別,至于如何使用,主要取決于我們對(duì)二者的熟悉程度。正如Martin Fowler所說:使用服務(wù)定位器時(shí),每個(gè)服務(wù)都依賴于服務(wù)定位器,它可以隱藏對(duì)其他實(shí)現(xiàn)的依賴關(guān)系,但是我們確實(shí)需要查看服務(wù)定位器,因此,是否采用定位器還是注入器主要決定于該依賴關(guān)系是否成問題。

講到這里我們借助于IServiceProvider接口實(shí)現(xiàn).NET Core中的服務(wù)定位器。如下:

除了以上寫法外,我們還可以通過實(shí)例化ServiceLocator的方式來獲取服務(wù),如下:

接下來我們寫一個(gè)簡(jiǎn)單的接口來驗(yàn)證是否正確:

不知道上述兩種寫法是否存在有什么不妥的地方,有的時(shí)候通過服務(wù)定位器的方式也非常清爽,因?yàn)楫?dāng)我們實(shí)例化最終具體實(shí)現(xiàn)時(shí)通過構(gòu)造注入依賴項(xiàng)時(shí),本沒有什么,但是若后期一旦需要增加或減少依賴項(xiàng)時(shí),我們同樣需要修改最終具體實(shí)現(xiàn),像這種情況是否可以考慮用服務(wù)定位器模式,直接通過服務(wù)定位器去獲取指定服務(wù),當(dāng)在具體方法里時(shí)我們每次都得去獲取服務(wù),反而不如在構(gòu)造器中一勞永逸注入。所以選擇注入器和定位器根據(jù)個(gè)人而選擇或者根據(jù)具體功能實(shí)現(xiàn)而定才是最佳。? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

控制反轉(zhuǎn)舉栗說明

上述我們通過代碼的形式來進(jìn)一步闡述了控制反轉(zhuǎn),在代碼的世界里,我們運(yùn)用控制反轉(zhuǎn)游刃有余,在現(xiàn)實(shí)生活里,我們運(yùn)用控制反轉(zhuǎn)也是得心應(yīng)手。

年末將至,全家歡聚一堂,這應(yīng)該是一年中最熱鬧的一次家庭聚會(huì)了吧,為了準(zhǔn)備年飯具體要提供哪些食材和食物作為家庭的一份子都得有基本了解,所以我們必須提前準(zhǔn)備好這些,這就像我們編寫一個(gè)沒有依賴注入的基本程序一樣,這是在自家做的情況,自家做飯吃完后,又不能抹抹嘴上油,拍拍屁股馬上走人,還得收拾不是,于是乎我們將年飯地點(diǎn)切換到飯店進(jìn)行,此時(shí)飯店類似取締了我們自備食材這一塊,飯店就像餐飲服務(wù)商一樣,我們不用自己做,飯店會(huì)給我們提供食物,它會(huì)根據(jù)我們的不同需求注入不同的餐飲服務(wù)。從自家-》飯店,整個(gè)流程控制權(quán)進(jìn)行反轉(zhuǎn),我們將年飯控制權(quán)交給了飯店,因?yàn)轱埖瓿蔀榱四觑堖@一事件的策劃者,它是我們能不能成功吃上年飯的必要條件,我們告訴飯店老板:有幾個(gè)人、帶了小孩、口味需重一點(diǎn)等等,我們需要做的就是提供一些基本參數(shù),然后飯店自會(huì)組織,我們并不需要關(guān)心和干涉細(xì)節(jié),他們會(huì)處理所有問題,一切就緒后會(huì)通知我們。

寫本文的目的是一直對(duì)控制反轉(zhuǎn)和依賴注入不太理解,在腦海中一直處于模糊的概念,同時(shí)呢,之前面試官問我關(guān)于依賴注入的理解,我居然支支吾吾的說成依賴倒置原則(Dependency Inversion Principle),千萬不要將依賴注入、依賴倒置、控制反轉(zhuǎn)搞混淆了,依賴倒置是完全不同的原理,雖然它也可以提供類之間的松散耦合和反轉(zhuǎn)依賴項(xiàng)。文中若有錯(cuò)誤之處,還望指出,感謝您的閱讀,謝謝。

總結(jié)

以上是生活随笔為你收集整理的不要叫我,我会叫你的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。