Ref: https://github.com/lichangqing2611/Cpp-Design-Patterns
什么是設計模式
“每一個模式描述了一個在我們周圍不斷重復發生的問題,以及該問題的解決方案的核心。這樣,你就能一次又一次地使用該方案而不必做重復勞動”。——Christopher Alexander
- 好的面向對象設計是面對變化,提高軟件的復用性。
- 先尋找變化點,然后在變化點上應用設計模式,而不是任何時間任何地方都用。
- 先寫代碼,而后采用設計模式進行重構。
如何解決復雜性?
- 分解
- 人們面對復雜性有一個常見的做法:即分而治之,將大問題分解為多個小問題,將復雜問題分解為多個簡單問題。
- 分析問題的思路。
- 抽象
- 更高層次來講,人們處理復雜性有一個通用的技術,即抽象。由於不能掌握全部的復雜對象,我們選擇忽視它的非本質細節,而去處理泛化和理想化了的對象模型。
- 編寫代碼的思路。
面向對象設計原則
1. 依賴倒置原則(DIP)
- 高層模塊(穩定)不應該依賴於低層模塊(變化),二者都應該依賴於抽象(穩定) 。
- 抽象(穩定)不應該依賴於實現細節(變化) ,實現細節應該依賴於抽象(穩定)。
MainForm -> Line\Rect => MainFrom -> Shape <- Line\Rect
2. 開放封閉原則(OCP)
- 對擴展開放,對更改封閉。
- 類模塊應該是可擴展的,但是不可修改。
對於改變應該盡量采用增加的方式對應,而不是修改的方式。
3. 單一職責原則(SRP)
- 一個類應該僅有一個引起它變化的原因。
- 變化的方向隱含着類的責任。
4. Liskov 替換原則(LSP)
- 子類必須能夠替換它們的基類(IS-A)。
- 繼承表達類型抽象。
5. 接口隔離原則(ISP)
- 不應該強迫客戶程序依賴它們不用的方法。
- 接口應該小而完備。
6. 優先使用對象組合,而不是類繼承
- 類繼承通常為“白箱復用”,對象組合通常為“黑箱復用” 。
小明的父類是人類,而不是小明的父親,通過理解的繼承關系有誤。
- 繼承在某種程度上破壞了封裝性,子類父類耦合度高。
- 而對象組合則只要求被組合的對象具有良好定義的接口,耦合度低。
7. 封裝變化點
- 使用封裝來創建對象之間的分界層,讓設計者可以在分界層的一側進行修改,而不會對另一側產生不良的影響,從而實現層次間的松耦合。
8. 針對接口編程,而不是針對實現編程
- 不將變量類型聲明為某個特定的具體類,而是聲明為某個接口。
- 客戶程序無需獲知對象的具體類型,只需要知道對象所具有的接口。
- 減少系統中各部分的依賴關系,從而實現“高內聚、松耦合”的類型設計方案。
重構技巧
- 靜態 -> 動態
- 早綁定 -> 晚綁定
- 繼承 -> 組合
- 編譯時依賴 -> 運行時依賴
- 緊耦合 -> 松耦合
從封裝變化角度對模式分類
組件協作:
單一職責:
對象創建:
對象性能:
接口隔離:
狀態變化:
數據結構:
行為變化:
領域問題:
現代較少用的模式
- Builder
- Mediator
- Memento
- Iterator
- Chain of Resposibility
- Command
- Visitor
- Interpreter
什么時候不用設計模式
- 代碼可讀性很差時
- 需要理解還很淺時
- 變化沒有顯現時
- 不是系統的關鍵依賴點
- 項目沒有復用價值時
- 項目將要發布時
Template Method
重點:
Observer/Event
重點: