SOLID 依賴反轉原則 Dependency Inversion Principle (DIP)

Finn
Jun 23, 2018

--

高層模組不應該依賴於低層模組。兩者皆應該依賴抽象。

抽象不應該依賴細節。細節應該依賴抽象

如果統一叫寶貝就不會有這個問題了

概述

如果高層模組依賴低層模組,這意味這低層模組的變動使得使用者高層模組會受影響,這樣是不合理的,應該是由高層行為去操作低層實作

所以必須將依賴反轉,使得高階不再依賴低階,而是中間透過抽象來達到依賴的反轉

該怎麼做呢?

一般設計直覺式的設計

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的方法抽象,利用共同抽象可以直接避免高層使用者依賴各個圖形的計算方法

在經常變化的需求底下,抽象和細節的彼此隔離,會讓程式碼非常容易維護

--

--