一個目標:管理變化,提高復用
掌握設計模式一個核心目標:管理變化,提高復用。在使用設計模式中發現並沒有實現復用,這就和設計初衷相違背了,說明代買寫的不好。
兩種手段:分解VS.抽象
在代碼設計中,該開始想要怎樣面向對象先要分解,比如這是梨,這是蘋果,這是香蕉建立這楊分解的思維,知道它們不同。但是呢我們很快建立抽象的思維,知道這一類都歸屬水果,然后就可以在思維管理里面或程序管理里面針對抽象進行統一的管理,比如水果有哪些功能的特征。
八大原則
- 依賴倒置原則(DIP)
- 高層模塊(穩定)不應該依賴於低層模塊(變化),二者都應該依賴於抽象(穩定) 。
- 抽象(穩定)不應該依賴於實現細節(變化) ,實現細節應該依賴於抽象(穩定)。
- 開放封閉原則(OCP)
- 對擴展開放,對更改封閉。
- 類模塊應該是可擴展的,但是不可修改。
- 單一職責原則(SRP)
- 一個類應該僅有一個引起它變化的原因。
- 變化的方向隱含着類的責任。
- Liskov 替換原則(LSP)
- 子類必須能夠替換它們的基類(IS-A)。
- 繼承表達類型抽象。
- 接口隔離原則(ISP)
- 不應該強迫客戶程序依賴它們不用的方法。
- 接口應該小而完備。
- 優先使用對象組合,而不是類繼承
- 類繼承通常為“白箱復用”,對象組合通常為“黑箱復用”。
- 繼承在某種程度上破壞了封裝性,子類父類耦合度高。
- 而對象組合則只要求被組合的對象具有良好定義的接口,耦合度低。
- 封裝變化點
- 使用封裝來創建對象之間的分界層,讓設計者可以在分界層的
- 一側進行修改,而不會對另一側產生不良的影響,從而實現層次間的松耦合。
- 針對接口編程,而不是針對實現編程
- 不將變量類型聲明為某個特定的具體類,而是聲明為某個接口。
- 客戶程序無需獲知對象的具體類型,只需要知道對象所具有的接口。
- 減少系統中各部分的依賴關系,從而實現”高內聚、松耦合"的類型設計方案。
重構技法
- 靜態 → 動態
- 早綁定→ 晚綁定
- 繼承→ 組合
- 編譯時依賴→ 運行時依賴
- 緊耦合→ 松耦合
從封裝變化角度對模式分類
C++ 對象模型
幾乎所有模式都歸屬第三種結構。繼承和組合在C++內存模型上沒有太大的區別,所以慎用繼承,優先組合,不過是帶指針的組合,如果是第二種會發生對象切割,而用指針更靈活,還可以指向它的子類。從耦合性來看,前兩種是緊耦合,第三種松耦合。
關注變化點和穩定點
設計模式的宗旨是:管理變化,提高復用。如果是所有都是變化的或穩定的,那用設計模式也沒有意義,設計模式是在管理變化實現穩定與變化隔離。
什么時候不用模式
- 代碼可讀性很差時
- 需求理解還很淺時
- 變化沒有顯現時
- 不是系統的關鍵依賴點
- 項目沒有復用價值時
- 項目將要發布時
經驗之談
- 不要為模式而模式
- 關注抽象類&接口
- 理清變化點和穩定點
- 審視依賴關系
- 要有Framework和Application的區隔思維
- 良好的設計是演化的結果
設計模式成長之路
- “手中無劍,心中無劍”: 見模式而不知
- “手中有劍,心中無劍”: 可以識別模式,作為應用開發人員使用模式
- “手中有劍,心中有劍”: 作為框架開發人員為應用設計某些模式
- “手中無劍,心中有劍”: 忘掉模式,只有原則