控制反轉(Inverse of Control, IoC)是一種設計模式,相依性注入(Dependency Injection)則是實踐IoC的一種方式,為什麼要IoC? 先來看看物件導向S.O.L.I.D.原則裡面的D.,依賴反轉原則(Dependency inversion principle,DIP)有下列特性:
- 高層次的模組不應該依賴於低層次的模組,兩者都應該依賴於抽象介面。
- 抽象介面不應該依賴於具體實現。
- 而具體實現則應該依賴於抽象介面。
這裡先看第1.點紅線的部分,這句話的意思就是指程式依賴性高。傳統寫程式是高階模組依賴低階模組,你會在某個高階模組method 中 new 個物件,然後執行裡面方法。這樣就是個依賴,若系統變大了,低階的實作方法又必須更換或調整時,工就多了。除了要更新實作低階方法,依賴它的各個(高階)模組也有可能要一併調整
(source:https://dotblogs.com.tw/lesterhsu0022/2017/12/28/182707)
在物件導向的世界中,我們對程式類別和物件相互依賴(相依性)的程度高低稱為耦合性。
(source : https://ithelp.ithome.com.tw/articles/10216539)
在 .NET (或某些物件導向程式語言)的世界裡,任何東西都是「物件」,而應用程式的各項功能便是由各種物件彼此相互合作所達成,例如:物件 A 呼叫物件 B,物件 B 又去呼叫 C。像這樣由類別之間相互呼叫而令彼此有所牽連,便是耦合(coupling)。物件之間的關係越緊密,耦合度即越高,程式碼也就越難維護;因為一旦有任何變動,便容易引發連鎖反應,非得修改多處程式碼不可,導致維護成本提高。
(source : https://www.huanlintalk.com/2011/10/dependency-injection-1.html)
- 什麼是Ioc(控制反轉)
IoC的概念是,把這些介面統整於容器(IoC Container)內,等到有需要使用時在注入於高階模組內,彼此間少了new這個動作,就能降低了依賴性。由原本的主動new,變成被動的被注入,IoC經典實現對象設計法則 好萊塢法則:“別找我們,我們找你”。可以用下面這張圖簡單解釋IoC。

以上大概解釋了一下什麼是控制反轉(IoC)這個設計模式概念,實作這種設計模式則是透過相依性注入(DI),目前也有很多IoC框架可以實踐IoC的設計原則(ex:AutoFact. Unity….)。簡單來說就是IoC + DI = 符合DIP原則的程式。
- 什麼是DI(依賴注入)
實作Ioc這種設計模式則是透過相依性注入(DI),目前也有很多IoC框架可以實踐IoC的設計原則(ex:AutoFact. Unity….)。簡單的來說一下,IoC就是透過DI的方式,不依賴實體物件,改依賴抽象介面。來解決高階模組依賴於低階模組的耦合問題。透過IoC + DI也讓程式符合了物件導向設計原則中的DIP(依賴反轉)
- 耦合的範例
下面程式中是一般物件導向的寫法,如果要使用到WriteLog時就要先建立一個的物件,這時的相依關係就是Module_A(高階模組)相依於TxtLogHelper(低階模組)才可以運作。簡單來說就是只要有使用到new建立物件的時候,建會產生相依性。
public class Module_A
{
var txtLog = new TxtLogHelper();
var log = txtLog.WriteLog();
}
public class TxtLogHelper
{
public string WriteLog()
{
return "Write txt log";
}
}
上面程式看起來沒有什麼問題,也是很常見的寫法。但是如果有一天,客戶突然提出個需求,想把log產出方式把txt改成匯出excel。快速修改程式後的結果可能如下:
public class Module_A
{
var excelLog= new ExcelLogHelper();
var log = excelLog.WriteLog();
}
public class TxtLogHelper
{
public string WriteLog()
{
return "Write txt log";
}
}
public class ExcelLogHelper
{
public string WriteLog()
{
return "Write excel Log";
}
}
程式修改好了後,我們可以看出因為相依性所產生的問題了:
Module_A相依於TxtLogHelper,造成了如果要替換別的產出log方式時,勢必要修改相依的程式,而必須要重新編譯。另外一個問題是如果還有其他的模組使用到了TxtLogHelper的話,就要一一的檢查程式把它找出來,做對應的修改跟重新編譯。
因為Module_A
(高階模組)依賴於TxtLogHelper
(低階模組),導致原本只要修改低階模組,卻要連著高階模組的程式也要一起改。這也違反了物件導向設計原則中的OPC(開放封閉)
Ref:
【架构与设计模式】控制反转和依赖注入 之 概念说明
菜雞新訓記 (6): 使用 依賴注入 (Dependency Injection) 來解除強耦合吧
Dependency Injection 筆記 (1)
我不依~我不依~什麼是相依性?
筆記-依賴注入-DI、控制反轉-IoC、依賴反轉原則-DIP
DIP. IOC. DI 基本概念