高層模組不應該依賴於低層模組。兩者皆應該依賴抽象。
抽象不應該依賴細節。細節應該依賴抽象
概述
如果高層模組依賴低層模組,這意味這低層模組的變動使得使用者高層模組會受影響,這樣是不合理的,應該是由高層行為去操作低層實作
所以必須將依賴反轉,使得高階不再依賴低階,而是中間透過抽象來達到依賴的反轉
該怎麼做呢?
Policy Layer 使用 Mechanism Layer、Mechanism Layer 使用 Utility Layer
一旦Mechanism Layer改變了,會使 Policy Layer也跟著改變,由此圖得知這種依賴關係是遞移的
所以要解決直接依賴的關係,高層可以提供一個抽象介面,像是在對低層模組說:
"嘿!我需要你提供這些服務,你就照我寫的上面的去實作"
透過抽象介面,解除了高層對低層的依賴關係,也解除了遞移關係
舉例
小明跟小美是情侶,但小明都會直接稱呼對方名稱,這時候只要有小三或換對象,就有講錯的可能
小明應該依賴女朋友抽象類別,之後統一叫女朋友,就再也不會有這個問題了
小美也會主動變成小明心中希望女友的類型
不過男女朋友間不是高低層,所以這只是舉例...
什麼時候需要遵守呢?
假設低層模組式類別是穩定的,像是原生提供的String,因為不太會改變,所以可以直接依賴
但我們寫的需求類別大多數都是不穩定的,需要利用抽象介面來隔離他們的不穩定
不遵守的話會?
如果直接依賴,低層模組在修改或替換時,高層模組將要在每個使用的地方做修改,也就是緊耦合
範例
利用書中的範例當Button 開關時 Lamp要亮或關的反應
以傳統直覺上的設計,高層的Button會直接使用Lamp的實作方法
這樣很明顯違反了DIP
所以我們將客戶使用者Button所需要的服務介面抽象化
再讓Lamp根據抽象化ButtonServer所需要的介面去實作
總結
DIP是拿來解決高層與低層直接的依賴導致,以往實作低層的實作改變會直接影響高層,使得策略會受到細節的變動而影響,例如範例中Lamp的turnOff的假如名稱改變,或是Button想控制別的物件,這都需要在高層上直接依賴低層模組實作
抽象的介面設計,應該要來自於高層服務介面而設計,以會改變的需求為主,像是Policy Layer範例
所以當高層依賴低層,轉變為低層依賴高層抽象,這就是依賴反轉了
在 開放封閉原則Open-Closed Principle中,也可以看到範例裡面 ShapeArea將getArea的方法抽象,利用共同抽象可以直接避免高層使用者依賴各個圖形的計算方法
在經常變化的需求底下,抽象和細節的彼此隔離,會讓程式碼非常容易維護