0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

淺談控制反轉(zhuǎn)和依賴注入

454398 ? 來源:博客園 ? 作者:田園里的蟋蟀 ? 2020-10-29 11:38 ? 次閱讀

控制反轉(zhuǎn)(Inversion of Control)是解決程序耦合問題的一種方案,還有種叫法是依賴注入(Dependency Injection),但我感覺Ioc(控制反轉(zhuǎn))是一種思想,DI(依賴注入)是實現(xiàn)這種思想的一種方式,或者說Ioc是一種概念,DI是這種概念的思想,不知道我這樣理解的對不對??赡芤婚_始接觸這些東西有點莫名其妙,園友們寫的一些東西也看得頭疼,至少我當時是這樣,如果你是像我一樣的菜鳥,請跟我一起學習下,不看代碼,我們先看一個生活中的例子-壓水井和自來水廠的故事。

小時候在農(nóng)村喝水都是自家打井或是用電水泵取水,想什么時候喝就什么時候喝,想喝多少就喝多少,很方便,而且不用花錢。但是有個問題是,家里面的房子要裝修或是重建,原來打的井已經(jīng)不適合新建的房子了,也就是說需要重新打井,這就很麻煩,建多少次房子,需要打多少次的井(當然土豪才這樣)。

我們先看這個小示例,其實如果抽象一點的話,有點類似工廠模式,為什么?我們分析下:上面例子中的水可以看成一個產(chǎn)品,每家的井或是電水泵可以看成一個工廠,自己根據(jù)自家的情況來“生產(chǎn)”出來水,只有一家有井或是電水泵還好(其他家去他家取水,但不現(xiàn)實),如果每家都有一個井或是電水泵,就有點工廠泛濫的情況發(fā)生了,可能會出現(xiàn):

水污染:每家都吃不上水,這里面的水出現(xiàn)問題就是產(chǎn)品出現(xiàn)問題,這樣我們就需要在每個工廠里面進行處理,就比如需要在每家的井或電水泵上安裝一個凈水器,顯然代價比較大,也不太現(xiàn)實。

整體搬遷:原來的井或電水泵用不了了,每家的井或電水泵就需要重新搞,可能不太現(xiàn)實,當然只是做個假設,細想一下,這個問題的根源其實就是井或電水泵太多了,也就是工廠泛濫。

上面所說的問題為什么會出現(xiàn)?其實就是依賴關系作祟,每一家都要依賴自家的井或電水泵,也沒辦法,畢竟人要喝水,總不能跑到地下暗河去喝吧,只能通過井或電水泵(工廠)來取水(調(diào)用),這個問題在編程中就是依賴倒置原則的反例,何為依賴倒置原則

高層次的模塊不應該依賴于低層次的模塊,他們都應該依賴于抽象。

抽象不應該依賴于具體,具體應該依賴于抽象。

第一點:高層次模塊(使用者)就是每戶人家,低層次模塊(被使用者)就是壓水井或電水泵,可以看出他們都是依賴于具體的對象,而并非依賴于抽象;第二點:水(抽象)依賴壓水井或電水泵(具體),人(具體)依賴壓水井(具體),而并非具體依賴于抽象??梢钥闯鲞@兩點完全不設和依賴倒置原則,怎么解決問題呢?請看下面。

自來水廠

上面的示例中其實有個三個對象:每戶人家、壓水井或電水泵、水,就是在探討他們?nèi)齻€這之間的依賴關系,明確這一點很重要。

隨著時代的發(fā)展,壓水井和電水泵慢慢消失在我們的視野中(當然現(xiàn)在還有很多落后的地方在用,比如像我老家),政府就在每個村莊或是幾個村莊之間建設自來水廠,為什么政府要建設自來水廠?難道他們都是搞編程的?知道工廠泛濫的壞處?哈哈,我覺得應該是多收點錢吧,你覺得呢?開個玩笑。

不管政府目的如何,但好像解決了工廠泛濫的一些問題,我們再來分析下有了自來水廠會有什么不同,我們畫個示意圖看下:

畫的比較丑(莫笑),但是簡單的意思還是可以表達的,圖中的人和水都是抽象的,地下水和水庫依賴于于抽象的水,A村的人和B村的人依賴于抽象的人,人和水怎么關系呢?這個就有自來水廠決定了,它讓你喝地下水,你就不能喝水庫的水。這就基本符合依賴倒置原則:抽象不依賴于具體,具體依賴于抽象

這中間關鍵在于自來水廠,沒了壓水井,有了自來水廠,我們看看上面壓水井的“工廠泛濫”問題能不能解決?

水污染:比如地下水出現(xiàn)問題,因為自來水廠不依賴地下水,而是依賴于抽象的水,地下水有問題,那我用水庫的水,水庫的水如果有問題,那我們用雨水凈化。。。我們?nèi)撕鹊降牟还苁裁此??反正都是水,不影響我們喝水就行了?/p>

整體搬遷:比如A村的人因為某些原因,要搬到B村,如果是上面壓水井的模式,幫過去就需要重新打井了,但是有了自來水廠,我只需要接個管線,按個水龍頭就行了,就這么簡單。

從上面的分析來看,建設自來水廠確實比壓水井可靠多了,回到我們這篇要講的正題-控制反轉(zhuǎn)(Ioc),你可能也有些明白了,其實自來水廠就可以看做是Ioc,用什么樣的水?給什么樣的人?都是自來水廠決定,好處就不用多說了,上面已經(jīng)講明,套用到編程里面是相同的道理,只可意會哦。

說到這里,你不禁有些驚訝,難道政府里面有系統(tǒng)架構師?哈哈笑過。

上面的示例,下面我們再來用代碼復述一下,畢竟理論要結(jié)合實踐。

壓水井的問題-依賴

壓水井模式有三個對象:人、壓水井、水,我們就用常規(guī)的方式簡單寫下代碼:

 1         /// 
 2         /// 村民
 3         /// 
 4         public class VillagePeople
 5         {
 6             public void DrinkWater()
 7             {
 8                 PressWater pw = new PressWater();
 9                 UndergroundWater uw = pw.returnWater();
10                 if (uw!=null)
11                 {
12                     Console.WriteLine("地下水好甜?。。?!");
13                 }
14             }
15         }
16         /// 
17         /// 壓水井
18         /// 
19         public class PressWater
20         {
21             public UndergroundWater returnWater()
22             {
23                 return new UndergroundWater();
24             }
25         }
26         /// 
27         /// 地下水
28         /// 
29         public class UndergroundWater
30         { 
31         }

上面的代碼就是簡單演示村民通過壓水井喝水的過程,因為村民不能直接取得水,只能通過壓水井取得地下水,很明顯我們可以看出之間的依賴關系:

VillagePeople依賴于PressWater

VillagePeople依賴于UndergroundWater

PressWater依賴于UndergroundWater

我們在做業(yè)務處理的時候,簡單的依賴關系可以用上面的方式處理,如果太復雜的話就不行了,牽一發(fā)而動全身總歸不是很好。

大家可能說,上面不是講到“工廠泛濫”問題,這邊怎么沒指出?因為PressWater某一方面其實就可以看做一個小工廠,每家的壓水井不一樣,這邊只是說某一種,“工廠泛濫”其實就是依賴作祟,上面的例子說明的是依賴關系,一樣的道理,所以下面就用這個例子來做一些東西。

壓水井的問題解決-依賴倒置

我們在講壓水井的時候提到過依賴倒置原則,這邊就不再說了,因為VillagePeople依賴于PressWater、VillagePeople依賴于UndergroundWater、PressWater依賴于UndergroundWater,我們可以把PressWater(壓水井)和UndergroundWater(地下水)抽象出來,UndergroundWater屬于水的一種,可以抽象為IWater,PressWater因為是獲取水的方式之一,可以抽象為IWaterTool,這邊就要面向接口編程了,根據(jù)依賴倒置原則,我們把上面的代碼修改一下:

 1         /// 
 2         /// 村民
 3         /// 
 4         public class VillagePeople
 5         {
 6             public void DrinkWater()
 7             {
 8                 IWaterTool pw = new PressWater();
 9                 IWater uw = pw.returnWater();
10                 if (uw != null)
11                 {
12                     Console.WriteLine("水好甜啊?。?!");
13                 }
14             }
15         }
16         /// 
17         /// 壓水井
18         /// 
19         public class PressWater : IWaterTool
20         {
21             public IWater returnWater()
22             {
23                 return new UndergroundWater();
24             }
25         }
26         /// 
27         /// 獲取水方式接口
28         /// 
29         public interface IWaterTool
30         {
31             IWater returnWater();
32         }
33         /// 
34         /// 地下水
35         /// 
36         public class UndergroundWater : IWater
37         { }
38         /// 
39         /// 水接口
40         /// 
41         public interface IWater
42         { }

從上面的代碼可以看出,UndergroundWater依賴接口IWater,PressWater依賴IWaterTool和IWater,VillagePeople依賴IWaterTool和IWater,這樣就符合依賴倒置原則了,都是依賴于抽象,從而降低耦合度,這樣當一個方式變化了不會影響到其他,地下水污染了,我可以通過別的獲取工具獲取水,而不至于沒水喝。

但是上面說的忽略了個問題,接口總是會被實現(xiàn)的,也就是總會執(zhí)行:IWaterTool pw =newPressWater();這樣耦合度就產(chǎn)生了,也就是VillagePeople依賴于PressWater,我們可以通過工廠參數(shù)來產(chǎn)生不同的獲取工具對象,這種方式表面上雖然解決了問題,但是實質(zhì)上代碼耦合度并沒有改變,怎么辦呢?請接著往下看。

自來水廠-Ioc

通過Ioc模式可以徹底解決上面我們提到耦合的問題,它把耦合從代碼中移出去,放到統(tǒng)一的XML文件中,通過一個容器在需要的時候把這個依賴關系形成,即把需要的接口實現(xiàn)注入到需要它的類中。就像自來水廠一樣,水的來源、水的去處都是它來決定,人們只要通過它來喝水就行了,而不需要考慮的太多。

早在微軟提供的一個示例框架PetShop中就有Ioc的體現(xiàn),只不過那時候不太懂,PetShop是通過反射創(chuàng)建對象,上面的代碼我們修改一下:

 1         /// 
 2         /// 村民
 3         /// 
 4         public class VillagePeople
 5         {
 6             public void DrinkWater()
 7             {
 8                 IWaterTool pw = (IWaterTool)Assembly.Load(ConfigurationManager.AppSettings["AssemName"]).CreateInstance(ConfigurationManager.AppSettings["WaterToolName"]);
 9                 IWater uw = pw.returnWater();
10                 if (uw != null)
11                 {
12                     Console.WriteLine("水好甜?。。?!");
13                 }
14             }
15         }

上面代碼中我們只需要在配置文件中添加獲取水工具的名稱WaterToolName就行了,因為一種工具對應獲取特定的一種水,所以水的種類不需要配置。地下水污染了,我們只需要在配置文件中修改一下WaterToolName就可以了。

Ioc模式,系統(tǒng)中通過引入實現(xiàn)了Ioc模式的Ioc容器,即可由Ioc容器來管理對象的生命周期、依賴關系等,從而使得應用程序的配置和依賴性規(guī)范與實際的應用程序代碼分開。其中一個特點就是通過文本的配置文件進行應用程序組件間相互關系的配置,而不用重新修改并編譯具體的代碼。

看到這里,是不是感覺Ioc模式有點“熱插拔”的意思?有點像USB一樣呢?

自來水廠運行-DI

如果把自來水廠看做Ioc,那我覺得依賴注入(DI)就是這個自來水廠的運行模式,當然其實是一個意思,依賴注入是什么?全稱Dependency Injection,我們從字面上理解下:需要的接口實現(xiàn)注入到需要它的類中,這就是依賴注入的意思。自來水廠獲取水源的時候,控制這個獲取水源的開關可以看做是依賴注入的一種體現(xiàn),話不多說,懂得就好。

依賴注入的方式有很多,就像控制獲取水源的開關有很多一樣。

構造器注入(Constructor Injection):Ioc容器會智能地選擇選擇和調(diào)用適合的構造函數(shù)以創(chuàng)建依賴的對象。如果被選擇的構造函數(shù)具有相應的參數(shù),Ioc容器在調(diào)用構造函數(shù)之前解析注冊的依賴關系并自行獲得相應參數(shù)對象;

屬性注入(Property Injection):如果需要使用到被依賴對象的某個屬性,在被依賴對象被創(chuàng)建之后,Ioc容器會自動初始化該屬性;

方法注入(Method Injection):如果被依賴對象需要調(diào)用某個方法進行相應的初始化,在該對象創(chuàng)建之后,Ioc容器會自動調(diào)用該方法。

有時間可以好好研究下依賴注入的各種方式,這邊我們就使用微軟提供的Unity實現(xiàn)依賴注入,方式是構造器注入,首先使用Nuget工具將Unity添加到項目中,安裝Unity需要.net framework4.5支持。

添加完之后,發(fā)下項目中多了Microsoft.Practices.Unity和Microsoft.Practices.Configuation兩個dll,代碼如下:

 1         /// 
 2         /// 人接口
 3         /// 
 4         public interface IPeople
 5         {
 6             void DrinkWater();
 7         }
 8         /// 
 9         /// 村民
10         /// 
11         public class VillagePeople : IPeople
12         {
13             IWaterTool _pw;
14             public VillagePeople(IWaterTool pw)
15             {
16                 _pw = pw;
17             }
18             public void DrinkWater()
19             {
20                 IWater uw = _pw.returnWater();
21                 if (uw != null)
22                 {
23                     Console.WriteLine("水好甜?。。?!");
24                 }
25             }
26         }

調(diào)用代碼:

1         static void Main(string[] args)
2         {
3             UnityContainer container = new UnityContainer();
4             container.RegisterType();
5             TestFour.IPeople people = container.Resolve();
6             people.DrinkWater();
7         }

首先我們創(chuàng)建一個Unity容器,接下來我們需要在容器中注冊一種類型,它是一個類型的映射,接口類型是IWaterTool,返回類型為PressWater,這個過程中就是要告訴容易我要注冊的類型。

比如自來水廠要用地下水作為水源,這時候操作員輸入命令,就是RegisterType,參數(shù)為IWaterTool、PressWater,下面就是調(diào)用Resolve生成對象,這個過程表示要把水輸送到哪戶人家,命令是Resolve,參數(shù)為VillagePeople,接下來就是直接打開水龍頭喝水了,很方便吧。

關于依賴注入其實有很多的東西,上面的示例只是拋磚引玉,有時間的話好好研究下,比如依賴注入的其他方式等等。
編輯:hfy

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • IOC
    IOC
    +關注

    關注

    0

    文章

    28

    瀏覽量

    10073
  • Unity
    +關注

    關注

    1

    文章

    127

    瀏覽量

    21702
收藏 人收藏

    評論

    相關推薦

    drv8412是怎么控制電機正反轉(zhuǎn)的?

    請問drv8412是怎么控制電機的正反轉(zhuǎn),謝謝
    發(fā)表于 09-20 07:13

    無刷電機正反轉(zhuǎn)由什么控制

    無刷電機(Brushless DC Motor, BLDC)是一種沒有電刷的電機,它通過電子換向器來控制電流的流向,從而實現(xiàn)電機的轉(zhuǎn)動。無刷電機的正反轉(zhuǎn)控制是其應用中的一個重要方面,涉及到電機的驅(qū)動
    的頭像 發(fā)表于 09-03 14:14 ?202次閱讀

    如何將行程開關接入正反轉(zhuǎn)控制電路

    行程開關是一種常見的限位開關,用于控制機械設備的行程。在正反轉(zhuǎn)控制電路中,行程開關可以用于實現(xiàn)自動控制,當設備到達預定位置時,自動切換到反向運動。以下是將行程開關接入正
    的頭像 發(fā)表于 08-26 16:35 ?188次閱讀

    變頻器控制電機的正反轉(zhuǎn)控制方式有哪些?

    變頻器是一種廣泛應用于工業(yè)領域的電力調(diào)整設備,它可以通過改變電源的頻率來實現(xiàn)電機的速度控制。在許多生產(chǎn)過程中,電機的正反轉(zhuǎn)控制是非常重要的,變頻器能夠通過不同的控制方式來實現(xiàn)這一功能。
    的頭像 發(fā)表于 08-14 17:04 ?455次閱讀

    簡單介紹plc如何控制電機正反轉(zhuǎn)

    PLC(可編程邏輯控制器)控制電機正反轉(zhuǎn)的過程可以通過以下步驟清晰地表示和歸納: 一、了解電機正反轉(zhuǎn)工作原理 電機正反轉(zhuǎn)是指電機能夠?qū)崿F(xiàn)順時
    的頭像 發(fā)表于 07-29 10:37 ?542次閱讀

    v20變頻器控制電機反轉(zhuǎn)怎么調(diào)

    以下是一些關于V20變頻器控制電機反轉(zhuǎn)的基本步驟和注意事項。 確認電機和變頻器的型號和規(guī)格是否匹配。 確保電機和變頻器的接線正確,包括電源線、控制線和電機線。 檢查變頻器的設置,確保其工作在正確
    的頭像 發(fā)表于 06-18 09:46 ?1372次閱讀

    PLC控制電動機正反轉(zhuǎn)電路的工作原理

    在工業(yè)自動化控制中,電動機作為動力源,其正反轉(zhuǎn)控制是常見的控制需求。傳統(tǒng)的電動機正反轉(zhuǎn)控制主要
    的頭像 發(fā)表于 06-17 09:37 ?1005次閱讀

    什么是離子注入?離子注入的應用介紹

    離子注入是將高能離子注入半導體襯底的晶格中來改變襯底材料的電學性能的摻雜工藝。通過注入能量、角度和劑量即可控制摻雜濃度和深度,相較于傳統(tǒng)的擴散工藝更為精確。
    的頭像 發(fā)表于 02-21 10:23 ?4067次閱讀
    什么是離子<b class='flag-5'>注入</b>?離子<b class='flag-5'>注入</b>的應用介紹

    plc怎么控制伺服電機正反轉(zhuǎn)

    電機的正反轉(zhuǎn),本文將詳細介紹其中的幾種方法。 一、硬件控制 開關控制:最簡單的方法是使用開關控制伺服電機的正反轉(zhuǎn)。通過將開關接入PLC的輸入
    的頭像 發(fā)表于 12-25 11:16 ?3434次閱讀

    Spring中依賴注入的四種方式

    在Spring框架中,依賴注入是一種核心的概念和機制。通過依賴注入,我們可以讓對象之間的依賴關系更加松散,并且能夠方便地進行單元測試和模塊化
    的頭像 發(fā)表于 12-03 15:11 ?1459次閱讀

    Spring依賴注入的方式

    Spring 是一個開源的輕量級框架,可以用于構建企業(yè)級應用程序。其最重要的特性之一是依賴注入(Dependency Injection,DI),這是一種設計模式,它可以幫助我們解耦代碼、提高
    的頭像 發(fā)表于 11-22 15:12 ?387次閱讀

    淺析變頻器外接開關控制正、反轉(zhuǎn)電路

    變頻器外接開關控制正、反轉(zhuǎn)電路
    的頭像 發(fā)表于 11-13 10:40 ?916次閱讀
    淺析變頻器外接開關<b class='flag-5'>控制</b>正、<b class='flag-5'>反轉(zhuǎn)</b>電路

    圖解變頻器外接繼電器正反轉(zhuǎn)控制電路

    變頻器外接繼電器控制反轉(zhuǎn)電路
    的頭像 發(fā)表于 11-09 16:43 ?1798次閱讀
    圖解變頻器外接繼電器正<b class='flag-5'>反轉(zhuǎn)</b><b class='flag-5'>控制</b>電路

    如何調(diào)整變頻器的正反轉(zhuǎn)?

    一、變頻器的正反轉(zhuǎn)控制方法變頻器實現(xiàn)電機正反轉(zhuǎn)的方法主要有兩種:外部控制和內(nèi)部控制。外部控制:外
    的頭像 發(fā)表于 11-09 08:07 ?1.4w次閱讀
    如何調(diào)整變頻器的正<b class='flag-5'>反轉(zhuǎn)</b>?

    如何調(diào)整變頻器的正反轉(zhuǎn)?

    變頻器實現(xiàn)電機正反轉(zhuǎn)的方法主要有兩種:外部控制和內(nèi)部控制。
    的頭像 發(fā)表于 11-07 16:27 ?7810次閱讀