標籤:
第11章 DIP:依賴倒置原則
DIP:依賴倒置原則:
a.高層模組不應該依賴於低層模組。二者都應該依賴於抽象。
b.抽象不應該依賴於細節。細節應該依賴於抽象。
11.1 層次化
展示了一個簡單的層次化方案:
高層的Policy層使用了低層的Mechanism層,而Mechanism層又使用了更細節的Utility層。它存在一個隱伏的錯誤特徵,那就是:Policy層對於其下一直到Utility層的改動都是敏感的。依賴關係是傳遞的。
展示了一個更為合適的模型:
每個較高層次都為它所需要的服務聲明一個抽象介面。較低層次實現了這些介面。每個高層類都通過該介面使用下一層。這樣高層就不依賴於低層。低層反而依賴於高層中聲明的抽象服務介面。
11.1.1 倒置的介面所有權
這裡的倒置不僅僅是依賴關係的倒置,它也是介面所有權的倒置。我們通常會認為工具庫應該擁有它們自己的介面。但是當應用了DIP時,我們發現往往是客戶擁有抽象介面,而它們的服務則從這些介面派生。
這就是著名的Hollywood原則:“Don‘t call us, we‘ll call you.(不要調用我們,我們會調用你。)” 低層模組實現了在高層模組中聲明並被高層模組調用的介面。
這裡所說的所有權僅僅是指介面是隨擁有它們的客戶程式發布的,而非實現它們的伺服器程式。介面和客戶程式位於同一個包或者庫中。這就迫使伺服器程式庫或者包依賴於客戶程式庫或者包。
當然,有時我們會不想讓伺服器程式依賴於客戶程式,特別是當有多分客戶程式但是伺服器卻僅有一份時。在這種情況下,客戶程式必須得遵循服務介面,並把它發布到一個獨立的包中。
11.1.2 依賴於抽象
程式中所有的依賴關係都應該終止於抽象類別或者介面。
- 任何變數都不應該持有一個指向具體類的引用。
- 任何類都不應該從具體類派生。
- 任何方法都不應該重寫它的任何基類中已經實現了的方法。
當然,每個程式都會有違反該啟發規則的情況。有時必須建立具體類的執行個體,而建立這些執行個體的模組將會依賴於它們。此外,該啟發規則對於那些雖然是具體但卻穩定的來來說似乎不大合理。如果一個具體類不太會改變,並且也不會建立其他類似的衍生類別,那麼依賴於它並不會造成損害。
比如,在大多數系統中,描述字串的類都是具體的。例如,在C#中的String。該類是穩定的。也就是說,它不太會改變。因此,直接依賴於它不會造成傷害。
如果一個不穩定的類的介面必須變化是,這個變化一定會影響到表示該類的抽象介面。這種變化破壞了由抽象介面維繫的隔離性。
可見,該啟發規則對問題的考慮有點兒簡單了。另一方面,如果看得更遠一點,認為是客戶模組或者層來聲明它們需要的服務介面,那麼僅當客戶需要時才會對介面進行改變。這樣,改變實現抽象介面的類就不會影響到客戶。
結論
使用傳統的過程化程式設計所建立出來的依賴關係結構、策略是依賴於細節的。這是糟糕的,因為這樣會使策略受到細節的改變的影響。物件導向的程式設計倒置了依賴關係結構,使得細節和策略都依賴於抽象,並且常常是客戶程式擁有服務介面。
事實上,這種依賴關係倒置正是好的物件導向設計的標誌所在。使用何種語言編程是無關緊要的。如程式的依賴關係是倒置的,它就是物件導向的設計。如果程式的依賴關係不是倒置的,它就是過程化的設計。
摘自:《敏捷式軟體開發 (Agile Software Development):原則、模式與實踐(C#版)》Robert C.Martin Micah Martin 著
轉載請註明出處:
JesseLZJ
出處:http://jesselzj.cnblogs.com
敏捷式軟體開發 (Agile Software Development):原則、模式與實踐——第11章 DIP:依賴倒置原則