依賴倒置原則(Dependency Inversion Principle: DIP)
高層模塊不應該依賴于底層模塊,二者應該都依賴于抽象
抽象不應該依賴于具體細節,細節應該依賴于抽象
這里的所有觀點摘抄自《敏捷軟件開發原則、模式與實踐》,原著Robert C. Martin,鄧輝等譯。
其實依賴倒置的原則很好理解,但是在實際應用中卻不容易識別出來。
現實中有很多這樣的例子,例如客廳里面要放置一個沙發。一種方案是,先去挑好沙發,然后根據沙發的形狀和尺寸來
然后把客廳改造成合適沙發的樣子。此時可以看到客廳的形狀就會嚴重依賴于沙發的形狀。另外一種辦法,則是預先
設計好房子的格局。然后去根據客廳的大小尺寸來挑選合適的沙發。
這個例子里面,房子就是高層模塊,不會經常變動,沙發屬于底層模塊。兩者依賴的抽象是什么呢,就是房子里面預留
的沙發的尺寸以及根據布局所決定的沙發的樣式顏色。
層次化
書里面引用了Booch的一段話:"所有結構良好的面向對象框架都具有清晰地層次定義,每個層次通過一個定義良好
的、受控的接口向外提供了一組內聚的服務。"
Booch是誰?UML語言的創立者。
也就是說,一個好的面向對象設計,都應該是層次清晰的。一旦有了層次,那就會有高層次和低層次之分,隨之而來
的也就有了依賴關系。我們習慣于把穩定的,不怎么發生改變的層稱為高層次。把經常發生變化的,可以被替代的稱為
低層次。
這樣的例子如,電腦內部的主板和顯卡,主板和內存,主板和CPU之間的關系。主板處于一個相對穩定的結構,所以屬于
高層次,而其他的配件都是經常發生變化的部分,所以屬于低層次。
回到DIP的話題,高層次和低層次究竟是一個什么樣的關系,究竟誰占主導地位,誰依賴于誰。我們先來看一下高層次
依賴于低層次。拿上面的例子來說,就是內存,顯卡,CPU占主導地位,主板使用了內存,顯卡,CPU所提供的方法。這樣
一來,無論是內存,顯卡還是CPU,只要其中一個進行更換,那么主板要相應的進行更換。這對消費者來說,簡直就是個
災難性的事情。
再來考慮,低層次依賴于高層次。這樣一來,主板只需要定義好需要的接口,低層的內存,CPU,顯卡根據這個接口來提供
具體的實現。
傳統概念中,高層次要適配低層次,因為是低層次提供了對外的接口,高層次只能依賴于低層次所提供的接口,沒有任何的
自主性。聯想到計劃經濟的產品的生產,就是這樣。DIP意味著主動權在(接口)高層次,在使用接口的人手上,高層次
需要什么,低層次就提供什么。同樣接口的作用也實現了高低層次之間的解耦。
著名的Hollywood原則:"Don't call us, we'll call you."
抽象
DIP中很關鍵的概念就是抽象。DIP建議所有的依賴關系都應該終止于抽象類或者接口。
- 任何變量都不應該持有指向具體類的指針或者引用
這點很好理解,具體類的變化會導致依賴關系的不穩定,從而違反了DIP。
- 任何類都不應該從具體類派生
依然是因為具體類的改變,會導致派生類依賴于具體類的改變。違反DIP。
- 任何方法都不應該覆寫任何基類中已經實現了的方法