[設計模式]設計模式原則
設計模式的目的: 隔離穩定和變化, 而不讓變化污染到穩定的部分, 所以需要判斷哪部分是變化的, 哪部分是穩定的
1. 依賴倒置原則(Dependency inversion principle, DIP)
依賴倒置原則: 分為兩句, 但核心都是穩定的部分不應該依賴變化的部分
- 高層模块(穩定)不應該依賴於低層模块(變化), 二者都應該依賴於抽象(穩定)
- 以下使用類來方便理解, 但模块是一個廣泛的概念, 它可以表示類、命名空間、庫、組件、服務等概念
- 高層的類: 核心業務邏輯
- 低層的類: 實現高層模块所需策略的具體策略
- 抽象: 接口, 用於隔離高層類和低層類
- 高層類使用接口來使用低層類(面向接口編程), 低層類根據接口定義實現細節
- 以下使用類來方便理解, 但模块是一個廣泛的概念, 它可以表示類、命名空間、庫、組件、服務等概念
- 抽象(穩定)不應該依賴於實現細節(變化), 實現細節應該依賴於抽象(穩定)
- 以下使用接口和類來方便理解, 但抽象是一個更廣泛的概念, 它可以是接口、契約等概念
- 抽象: 接口
- 實現細節: 實現類
- 接口不應該根據實現類設計(應該只關注希望實現的行為, 而不關注具體行為的細節), 實現類應該根據接口設計
- 以下使用接口和類來方便理解, 但抽象是一個更廣泛的概念, 它可以是接口、契約等概念
2. 開放封閉原則(The Open/Closed Principle, OCP)
開放封閉原則:
- 對擴展開放, 對修改封閉: 如果直接對代碼進行修改, 那麼可能會引入很多麻煩, 比如引入新的Bug、 破壞原有設計、 所有依賴修改後的代碼的模块都需要重新測試等
- 類模块應該是可擴展的, 但是不可修改: 接口就是實現可擴展的方法之一
但實際上不是拒絕全部的修改, 而是實現易變化的部分和穩定的部分分離, 比如工廠模式等內容
3. 單一職責原則(Single responsibility principle, SRP)
單一職責原則: 一個類應該只對一個角色負責
- 一個類應該僅有一個引起它變化的原因: 一個類只應該負責一個業務, 因為業務的變化會導致類的變化
- 變化的方向隱含著類的責任: 如果類會因為某個業務變化而變化, 那麼這個類就對這個業務的角色負責
4. Liskov 替換原則(Liskov Substitution Principle, LSP)
Liskov 替換原則:
- 子類必須能夠替換它們的基類(IS-A)
- 繼承表達類型抽象
- 類型: 在程式設計中, 一個類型就是一個契約, 表示任何屬於這個類型的物體都具備哪些屬性和行為
- 類型抽象: 把需要用到的一個概念定義為一個類型, 也就是抽象出需要用的屬性和行為
- 繼承必須遵守父類的契約
5. 接口隔離原則(Interface Segregation Principle, ISP)
接口隔離原則:
- 不應該強迫客戶程序依賴它們不用的方法: 因為客戶程序不應該為它不需要的功能而付出代價
- 接口應該小而完備: 一個接口應該只代表一個業務, 否則它的泛用性會受到限制, 因為如果代表了多個業務, 只有同時需要多個業務時才會使用這個接口
- 小: 接口應該只代表一個業務, 服務於同一個目的或者角色
- 完備: 接口應該能單獨地代表一個業務, 而不需要多個小接口才能實現
6. 優先使用對象組合, 而不是類繼承
優先使用對象組合, 而不是類繼承:
- 類繼承通常為"白箱復用", 對象組合通常為"黑箱復用"
- 白箱復用: 箱子對用戶不是透明的, 需要考慮到箱子的內部結構。子類不僅知道了父類的公開行為, 還和父類的內部實現細節緊密地聯擊在一起。如果子類使用了父類的行為, 那麼子類的行為就會直接依賴於父類的具體實現, 這時父類的實現變化了(但功能沒變化)可能會意外地破壞子類的功能
- 黑箱復用: 箱子對用戶是透明的, 只需要知道箱子的作用就可以了。容器類只要知道組合對象的功能就可以, 無論組合對象內部怎麼變化, 只要它的功能沒有變化, 那麼就不會破壞容器類的功能
- 繼承在某種程度上破壞了封裝性, 子類父類耦合度高
- 對象組合只要求被組合的對象具有良好定義的接口, 耦合度低
7. 封裝變化點
封裝變化點: 使用封裝來創建對象的之間的分界層, 讓設計者可以在分界層的一側進行修改, 而不會對另一側產生不良的影響, 從而實現層次間的松耦合
- 在需要分界的位置使用接口或者依賴注入來實現層次間的解耦, 但不能無限解耦, 只在有需要的地方去解耦, 比如架構間工具的連接, 和第三方的API等地方
8. 針對接口編程, 而不是針對實現編程
針對接口編程, 而不是針對實現編程:
- 不將變量類型聲明為某個特定的具體類, 而是聲明為某個接口
- 客戶程序無需獲知對象的具體類型, 只需要知道對象所具有的接口
- 減少系統中各部分的依賴關係, 從而實現"高內聚、松耦合"的類型設計方案
也就是面向接口編程
