最近沒事再次翻開《敏捷軟體開發:原則、模式與實踐》看,發現以前似懂非懂的東西突然就看懂了,get到了講的重點。
SOLID(單一職責原則、開放—封閉原則、里氏替換原則、介面隔離原則以及依賴倒置原則)是由羅伯特·C·馬丁引入,成為了物件導向設計中的五個基本原則。當這些原則被一起應用時,它們使得一個程式設計師開發一個容易進行軟體維護和擴充套件的系統變成可能。
1 單一職責原則(SRP)
定義:一個類應該只有一個發生變化的原因
為何把這兩個職責分離到分離到單獨的類中很重要呢?因為每一個職責都是變化的一個軸線。當需求變化時,該變化會反映為類的職責變化。如果一個類承擔了多於一個的職責,那麼引起它變化的原因就會有多個。如果一個類承擔的職責過多,就等於把職責耦合在了一起。一個職責的變化可能會削弱或者抑制這個類完成其他職責的能力。這種耦合會導致脆弱的設計,當變化發生時,設計會遭受到意向不到的破壞。
在SRP中,我們把職責定義為變化的原因,如果你能夠想到多於一個的動機去改變一個類,這個類就具有多於一個的職責。有時,我們很難注意到這一點。我們習慣於以組的形式去考慮職責。
僅當變化發生時,變化的軸線才具有實際意義。如果沒有徵兆,那麼應用SRP或者任何其他原則都是不明智的。
軟體設計真正要做的許多工作,就是發現職責並把那些職責相互分離。其餘原則都會以這樣或者那樣的方式回到這個問題上。
2 開放封閉原則(OCP)
定義:軟體實體(類、模組、函式等)應該是可以擴充套件的,但是不可修改。
如果程式中的一處改動就會產生連鎖反應,導致一系列相關模組的改動,那麼設計就具有僵化性的臭味。OCP建議我們應該對系統進行重構,這樣以後對系統再進行那樣的改動時,就不會導致更多的修改。如果正確地應用OCP,那麼以後進行同樣的改動時,就只需要新增新的程式碼,而不必改動已經正常執行的程式碼。
怎樣可能在不改動模組原始碼的情況下去更改它的行為呢?如果不更改一個模組,又怎麼能夠去更改它的功能呢?答案就是抽象。
策略模式(STARTEGY)和模板方法(TEMPLATE METHOD)模式是滿足OCP最常用的方法。應用它們,可以把一個功能的通用部分和實現細節部分清晰的分離開來。
在許多方面,OCP都是物件導向設計的核心所在。遵循這個原則可以帶來物件導向技術所聲稱的巨大好處:靈活性、可重用性、以及可維護性。開發人員應該僅僅對程式中呈現出頻繁變化的那些部分做出抽象。拒絕不成熟的抽象和抽象本身一樣重要。
3 里氏替換原則(LSP)
定義:子型別必須能夠替換掉它們的基型別。
LSP得出一個非常重要的結論:一個模型如果孤立的看,並不具有真正意義的有效性。模型的有效性只能通過它的客戶程式來表現。
LSP基於契約的設計(Design By Contract,DBC)。使用DBC類的編寫者顯示地規定針對該類的契約。客戶程式碼的編寫者可以通過該契約獲悉可以依賴的行為方式。契約是通過為每個方法宣告前置條件和後置條件來指定的。要使一個方法得以執行,前置條件要為真。執行完畢後,該方法的後置條件為真。派生類的行為方式和輸出不能違反基類已經確立的任務限制,基類的使用者不應該被派生類的輸出擾亂。
OCP是OOD(物件導向設計)中很多說法的核心。如果這個原則應用得有效,應用程式就會具有更強的可維護性、可重用性以及健壯性。LSP是使OCP成為可能的主要原則之一。正是子型別的可替換性才使得使用基型別表示的模組在無需修改的情況下可以擴充套件。這種可替換性必須是開發人員可以隱式依賴的。這樣如果沒有在程式碼中顯式地支援基型別的契約,那麼就必須很好地、廣泛地理解這些契約。子型別正確的定義是可替換的,可替換性通過隱式或者顯式的契約來定義。
4 介面隔離原則(ISP)
定義:不應該強迫客戶程式依賴並未使用的方法。
這個原則用來處理“胖”介面所存在的缺點。如果類的介面不是內聚(內聚(Cohesion)是一個模組內部各成分之間相關聯程度的度量)的,就表示該類具有“胖”介面。
如果強迫客戶程式依賴那些不使用的方法,那麼這些客戶程式就面臨著由於這些未使用的方法的改變所帶來的變更。這無意中導致了所有客戶程式之間的耦合。換言之,如果一個客戶程式依賴於一個含有它不使用的方法的類,但是其他客戶卻確實要用這個方法,那麼當其實客戶要求這個類改變時,就會影響到這個客戶程式。分離客戶就是分離介面。
客戶程式應該僅僅以來於它們實際呼叫的方法。通過把胖類介面分解為多個特定於客戶程式的介面,可以實現這個目標。每個特定於客戶程式的介面僅僅宣告它的特定客戶或者客戶組呼叫的那些函式。接著,該胖類就可以繼承所有特定於客戶程式的介面,並實現它們,這就解除了客戶程式和沒有呼叫的方法間的依賴關係,並使客戶程式之間互不依賴。
5 依賴倒置原則(DIP)
定義:
a.高層模組不應該依賴於低層模組。二者都應該依賴於抽象。
b.抽象不應該依賴於細節。細節應該依賴於抽象。
該原則是框架設計的核心原則。
倒置的含義
為什麼使用"倒置”,倒置是較於傳統的軟體開發,比如結構化分析和設計,總是傾向於建立一些高層模組依賴於低層模組、策略依賴於細節的軟體結構。一個設計良好的物件導向的程式,其依賴程式結構相對於傳統的過程式方法設計的通常結構而言就是被“倒置"了。
倒置的是什麼?
DIP不僅僅是依賴關係的倒置,它也是介面所有權的倒置。客戶擁有介面所有權,而它們的服務者則從這些介面派生。
由客戶模組或者層來宣告它們所需要的服務介面,那麼僅當客戶需要時才會對介面改變。這樣改變實現抽象介面的類就不會影響到客戶。
層次化:
所有結構良好的物件導向架構都具有清晰的層次定義,每個層次通過定義一個良好的、受控的介面向外提供了一組內聚的服務。
面象物件的程式設計倒置了依賴關係,使得細節和策略依賴於抽象,並且常常是客戶擁有服務介面。依賴關係的倒置正是好的物件導向設計的標誌所在。是實現許多物件導向技術所宣稱的好處的基本低層機制。它的正確應用對於建立重用的框架來說是必需的。同時它對於構建在變化面前富有彈性也是重要的。由於抽象和細節彼此隔離,所以程式碼也非常容易維護。
相關閱讀