11. DIP: 依賴反向原則

反著走,是為了走更長遠的路

Posted by willsbor Kang on 2019-05-06

DIP: 依賴反向原則

最靈活的系統是「原始碼的依賴關係只涉及抽象不涉及具體」的那些系統

最理想,是沒有具體的東西該被依賴,像是使用 use, import, include 之類的,只有抽象的介面被包含進來。但是如果「全」照這個想法去做,是不切實際的,因為軟體系統必須依賴許多具體的機制,例如 Swift 中的 String, Int … 試圖將它變成抽象的,是不切實際的,也是不可避免的。

Chapter 32 有講到不對稱的婚姻,與你使用的程式語言 (e.g. swift, java, c/c++...) 到終老,是無法避免的誓言 XD

因此我們傾向忽略作業系統和平台的穩定背景,容忍那些具體的依賴,我們幾乎可以信任他們是不會改變的。

因此「避免依賴系統中容易變化的具體元素」,正式 DIP 所討論的。

穩定的抽象

好的軟體設計師和架構師會努力減少介面的變動性。他們試圖找到增加實作功能但是不必更改介面的方式。

  • 不要參考易變的具體類別
    建立物件需要有嚴格限制,參考抽象的介面,像是使用 abstract factory
  • 不要從易變的具體類別衍生
    繼承是強大且嚴格的,因此使用的時候必須小心警慎
  • 不要改寫具體函式
    具體函式通常要求原始碼的依賴,當你 override 時,這些依賴是不會消失的。
  • 永遠不要提到任何具體和易變的名稱
    就是守則本身

工廠

為了遵守這些守則,建立易變的具體物件需要進行特殊的處理。

將系統分成兩個部分:一部分是抽象,一部分是具體,抽象元件包含應用程式的所有高層業務規則。具體元件包含了處理業務規則的實作

控制流在原始碼依賴性的相反方向上穿越過「抽象/實作」的界線。原始碼依賴性與控制流是相反的–這就是我們為什麼稱作依賴反向原則

具體元件

在架構中,實作具體元件的部分,還是有實作的依賴關係,這是典型會出現違反 DIP 的地方,這無法完全消除,但是可以將其收集到少量的具體元件中,例如 main

總結

DIP 會一次又一次的出現,這就是我們的架構圖中,最顯見的組織原則。

之前在處理 Swift 中的 Date 物件時,也有用到這個概念,雖然他是系統/程式語言的基礎物件,但是當他被建立時,無法透過其他的規則,知道他正確的值,因此會無法測試。所以還是需要透過 abstract factory,將相依性分開,透過抽象介面產生 Date,這樣才有機會在測試時候得到正確的答案。

這是個一開始不容易理解的情況,但是經過多次實作後,且以「測試」當作目標,這個概念會越來越清晰。