近期工作上剛好比較常在跟同事討論到一些專案結構和設計問題,但是常常會發生臨時忘掉如何解釋那些專有名詞和原則的窘境。覺得這樣很不行,決定趁現在剛看完後,寫點東西紀錄。
依賴注入 (DI, Dependency Injection)
簡單名詞解釋(可略過):
Dependency,依賴,顧名思義,一個物件需要另一個物件存在;如果不存在,這個物件就不能獨立運作。
Injection,注入,就是將另一個物件直接傳入需要使用這個物件的地方,這裡使用 Injection 這個關鍵字形容這個行為。
上面只是簡單的根據兩個英文字單獨的意思拆解,其實這應該要視為同一個字,因為是形容一個完整的行為。基本上可以無視各自文字的解釋,專注於這個名詞代表的意思即可。當然,因為母語是中文的關係,可能還是會習慣拆兩個單字,如果可以幫助記憶,個人倒是覺得也無不可。
為何要用:
基於物件導向設計(OOP),應用程式都是以類別的實例(就是物件),來實現各種功能,這種情況下,必然會出現其中一個物件需要另外一個物件的功能。
物件之間的互相依賴,容易造成高偶合(High coupling)的問題,一旦修改一個物件,很大的可能會需要修改一大堆連帶的物件。這種情況下,造成的風險可能會完全無法預期。
為了解決耦合問題,所以才需要用 Dependency Injection。
如何使用:
簡單說,藉由外部傳入的物件應該在外面就先實例化(Instanced)完成(new ClassName()),然後在需要的地方理應用內部變數來存放後使用。
* (實例化在OOP語言就是 new Car(),Python 這邊就是 Car())
Dependency Injection 的大原則就是 Injection (注入)的物件不應該在內部進行實例化。以前我不懂為何要在外部進行。說穿了,就是因為如果在內部進行實例化,一旦需要修改名稱或是實例化的參數。舉凡修改參數的數量、類型以及順序。這些全部都要根據新的格式進行改動,這個在大型系統中是非常複雜且成本很高的一件事情。所以,就應該是設計一個良好的物件可供需要的物件使用。並且不隨意更動其成員(Function or Parameter)。
而制定規範,並且根據規範實作,這就是介面(Interface)負責的項目。因此,多數時候,我們會先制定一個共用的介面,需要實作的類別們,都需要先實現介面的成員。
以上為介面隔離原則 (ISP, Interface Segregation Principle) 的基本應用。
最終,需要每一個被別的物件呼叫的物件們,都擁有介面制定好的成員。這個解決方案,就是依賴反轉 (DIP, Dependency Inversion Principle)。
總結:
筆記到後面,突然發現其實我早就在很多地方用過它了,只是一直沒有太多深入思考這兩者之間的關聯性。
由於此文作為一個快速筆記,加強記憶為用。