設計原則之-依賴倒置原則(Dependency Inversion Principle, DIP)

定義

High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend on details. Details should depend on abstractions.

  • 高層模塊不應該依賴於低層模塊,兩者都應該依賴於抽象。
  • 抽象不應該依賴於細節。細節應該依賴於抽象。

依賴倒置

簡而言之就是「面向接口編程」。

核心概念

依賴接口而不依賴細節(實現)。這樣做的好處就是系統更具靈活性。底層的實現不會對高層的調用產生任何影響,我們甚至可以替換掉原來的實現,新寫一套實現。

接口是一份契約,約定了方法的功能,傳入的參數,輸出的值。高層只調用接口傳入參數獲得返回值,而實現層則實現方法,處理具體參數,執行某些任務,然後將結果返回給高層。這一切都是由接口來約束的。

實例

獲取天氣信息

天氣服務

  • WeatherService接口中規定了具體的方法,以及方法的參數、返回值等信息。
  • Client接收一個接口的實現,但是不管是哪個實現。
  • WeatherInfo是接口中約定的返回值。包括日期、溫度、溼度、風力以及天氣信息等。

這樣做的好處就是,比如一開始我們用的是百度的天氣接口。但是百度接口因爲種種原因停用了,然後換成了新浪的接口。百度的天氣API和新浪的天氣API返回的結果肯定是不一樣的。但是這裏的Client不用關心這些,因爲接口中已經規定了具體的返回值的格式,而對於API中數據格式的差異是由BaiduWeatherServiceSinaWeatherService來處理的。BaiduWeatherServiceSinaWeatherService需要解析天氣API中的數據,然後再封裝成指定的格式。而API中返回的其他的信息(比如未來N天的天氣)則被實現類忽略。因爲接口中規定的返回結果中不需要。

依賴倒置可以減少類與類之間的耦合性,降低並行的開發風險。

依賴倒置就好似我們現在的前後端分離式的開發方式,定義好接口後,前端按照定義的接口規範來調用接口,然後使用符合接口規範的模擬數據來調試功能。後端按照接口規範中的定義實現接口,返回數據。

依賴於抽象

以下內容摘自《敏捷軟件開發:原則、模式與實踐》

一個稍微簡單但仍然非常有效的對於DIP的解釋,是這樣一個簡單的啓發式規則:「依賴於抽象」。這是一個簡單的陳述,該啓發式規則建議不應該依賴於具體類–也就是說,程序中的依賴關係都應該終止與抽象類或接口。

根據這個啓發式規則。可知:

  • 任何變量都不應該持有一個紙箱具體類的指針或引用
  • 任何類都不應該從具體類派生
  • 任何方法都不應該覆寫它的任何基類中的已實現了的方法。