一文get到SOLID原則的重點

 最近沒事再次翻開《敏捷軟件開發:原則、模式與實踐》看,發現以前似懂非懂的東西突然就看懂了,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不僅僅是依賴關係的倒置,它也是接口所有權的倒置。客戶擁有接口所有權,而它們的服務者則從這些接口派生。

由客戶模塊或者層來聲明它們所需要的服務接口,那麼僅當客戶需要時才會對接口改變。這樣改變實現抽象接口的類就不會影響到客戶。

層次化:

所有結構良好的面向對象架構都具有清晰的層次定義,每個層次通過定義一個良好的、受控的接口向外提供了一組內聚的服務。

面象對象的程序設計倒置了依賴關係,使得細節和策略依賴於抽象,並且常常是客戶擁有服務接口。依賴關係的倒置正是好的面向對象設計的標誌所在。是實現許多面向對象技術所宣稱的好處的基本低層機制。它的正確應用對於創建重用的框架來說是必需的。同時它對於構建在變化面前富有彈性也是重要的。由於抽象和細節彼此隔離,所以代碼也非常容易維護。

相關閱讀

SOLDI原則之DIP:依賴倒置原則