Image

昨天和朋友聊到面試被考了 DI 和 IOC,心想「該不會現在是貼我的筆記賺廣告費的好機會?!」

結果沒找到機會爽貼一波。為了彌平這股不甘(?),決定插播先把之前的依賴注入筆記分享上來:
菜雞新訓記 (6): 使用 依賴注入 (Dependency Injection) 來解除強耦合吧

延伸閱讀:菜雞與物件導向 (14): 依賴反轉原則


既然都分享上來了,也就順便複習複習、整理一下當時的思路。我們可以先找到一個藏在標題裡的問題:為什麼我們需要解耦合?

假設現在有間小小公司,老闆請來了小明當工程師,並請他開工撰寫產品程式碼。

當「撰寫產品程式」對「工程師」直接依賴的時候,狀況可能是這樣的:

public Product Work() // 撰寫產品程式
{
    Ming programmer = new Ming();
    var product = programmer.Programming();
    return product;
}

過一陣子,老闆發現小明寫出來的東西似乎不太行,於是把小明趕走,另外請了小華。這時候因為用到的類別不一樣了,我們就必須要改一次程式碼:

public Product Work()
{
    Hua programmer = new Hua(); // 把小明改成小華
    var product = programmer.Programming();
    return product;
}

又過了好一陣子,老闆又另外請了小美來工作。於是又要再改一次,而且小美的工作方式甚至不叫做 Programming,而是 Coding:

public Product Work()
{
    Mei programmer = new Mei(); // 把小華改成小美
    var product = programmer.Coding(); // 呼叫方法也要改
    return product;
}

現在有感覺到一點問題了嗎?如果一直換人,程式碼不就每次都要修改?

遇到這個問題之後,我們可以從依賴反轉原則中找到一些靈感。如同筆記提到的:

面對這樣的困境,依賴反轉原則告訴我們:高階模組不應該依賴於低階模組。兩者都應該依賴抽象。我們可以不要讓高階模組直接去依賴低階模組,而是使用抽象的、具有契約精神的介面來對他們進行隔離。

如此一來,只要介面的契約成立了,高階模組就可以專心做好自己的事情(職責),而不用去管低階模組的方法名稱之類的鳥事、低階模組也只要專注在實作介面要求的契約內容就行了。

從這邊延伸到介面後,我們也可以理解為什麼我們需要反轉了,甚至可以說反轉之後的概念才更接近我們平常寫程式的思路:

並不是高階模組去依賴低階模組,而是高階模組提出它需要的功能,低階模組去實作出這些功能、達成高階模組的目標。

但我們想要達成這個概念,還是需要一些實作上的技巧。於是我們就有了依賴注入:

我們使用功能之前,必須先建立該類別的實例,也就是 new Ming(),那麼,我們不就還是直接依賴了實作嗎?

面對這個問題,大大們提出了許多個解決的方法,其中最常見的就是:控制反轉 (Inversion of Control, IoC)。

思路非常的簡單:我們把實例的建立和實例的使用切分開來就好了,讓建立的去建立、讓使用的去使用,不再是由高階模組去建立並控制低階模組,而是我們讓一個控制反轉中心去建立低階模組,然後高階模組要使用的時候再把這個低階模組交給高階模組使用。

接著就可以把建立實例的部分都掃去控制反轉中心(=組合根),然後用各種姿勢(?)拋進去給需要的地方使用

後續比較偏 .Net Core 實作的部份就不覆盤了。 而且我沒有 Discord Nitro 所以發不了那麼長

離這篇筆記也過了兩年多,現在還是快樂無腦把注入丟給 .Net 幫我做

趁這個機會回頭偷看一下,不然面試想不起來就不好了 xD

那麼,今天的轉貼就先到這邊。明天見 ><