設計模式(Design Pattern)
- 是什么
是一套被反復使用、多數人知曉的、經過反復編寫的、代碼設計經驗的總結 - 目的:
使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
設計模式的六大原則:
1. 總原則-開閉原則
定義
對擴展開放,對修改封閉。
在程序需要進行拓展的時候,不能去修改原有的代碼,而是要擴展原有代碼,實現一個熱插拔的效果。所以一句話概括就是:為了使程序的擴展性好,易于維護和升級。
為了滿足開閉原則,需要對系統進行抽象化設計,抽象化是開閉原則的關鍵。
原因
任何軟件都需要面臨一個很重要的問題,即它們的需求會隨時間的推移而發生變化。當軟件系統需要面對新的需求時,我們應該盡量保證系統的設計框架是穩定的。如果一個軟件設計符合開閉原則,那么可以非常方便地對系統進行擴展,而且在擴展時無須修改現有代碼,使得軟件系統在擁有適應性和靈活性的同時具備較好的穩定性和延續性。
2. 單一職責原則---一個類只負責一項職責
定義
不要存在多于一個導致類變更的原因。通俗的說,即一個類只負責一項職責
問題由來:
類T負責兩個不同的職責:職責P1,職責P2。當由于職責P1需求發生改變而需要修改類T時,有可能會導致原本運行正常的職責P2功能發生故障。
原因
一個類承擔的職責過多,就相當于將這些職責耦合在一起,當其中一個職責變化時,可能會影響其他職責的運作
解決方案
遵循單一職責原則。分別建立兩個類T1、T2,使T1完成職責P1功能,T2完成職責P2功能。這樣,當修改類T1時,不會使職責P2發生故障風險;同理,當修改T2時,也不會使職責P1發生故障風險。
3. 里氏替換原則---子類可完整實現父類的業務
定義
所有引用基類的地方必須能透明地使用其子類的對象。
任何基類可以出現的地方,子類一定可以出現。里氏替換原則是繼承復用的基石,只有當衍生類可以替換基類,軟件單位的功能不受到影響時,基類才能真正被復用,而衍生類也能夠在基類的基礎上增加新的行為。
問題由來
有一功能P1,由類A完成。現需要將功能P1進行擴展,擴展后的功能為P,其中P由原有功能P1與新功能P2組成。新功能P由類A的子類B來完成,則子類B在完成新功能P2的同時,有可能會導致原有功能P1發生故障。
解決方案
當使用繼承時,遵循里氏替換原則。類B繼承類A時,除添加新的方法完成新增功能P2外,盡量不要重寫父類A的方法,也盡量不要重載父類A的方法。里氏替換原則中,子類對父類的方法盡量不要重寫和重載。因為父類代表了定義好的結構,通過這個規范的接口與外界交互,子類不應該隨便破壞它
- 里氏替換原則通俗的來講就是:子類可以擴展父類的功能,但不能改變父類原有的功能。它包含以下4層含義:
- 子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法。
- 子類中可以增加自己特有的方法。
- 當子類的方法重載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬松。
- 當子類的方法實現父類的抽象方法時,方法的后置條件(即方法的返回值)要比父類更嚴格。
4. 依賴倒轉原則---面向接口編程
面向接口編程,依賴于抽象而不依賴于具體。寫代碼時用到具體類時,不與具體類交互,而與具體類的上層接口交互。
定義
高層模塊不應該依賴低層模塊,二者都應該依賴其抽象
抽象不應該依賴細節,細節應該依賴抽象。
問題由來
類A直接依賴類B(B給A發消息),假如要將類A改為依賴類C,則必須通過修改類A的代碼來達成。這種場景下,類A一般是高層模塊,負責復雜的業務邏輯;類B和類C是低層模塊,負責基本的原子操作;假如修改類A,會給程序帶來不必要的風險。
解決方案
將類A修改為依賴接口I,類B和類C各自實現接口I,類A通過接口I間接與類B或者類C發生聯系,則會大大降低修改類A的幾率。
5. 接口隔離原則---客戶端不應該依賴它不需要的接口
Interface Segregation Principle
:每個接口中不存在子類用不到卻必須實現的方法,如果不然,就要將接口拆分。使用多個隔離的接口,比使用單個接口(多個接口方法集合到一個的接口)要好。
定義
客戶端不應該依賴它不需要的接口,一個類對另一個類的依賴應該建立在最小的接口上。
問題由來
類A通過接口I依賴類B,類C通過接口I依賴類D,如果接口I對于類A和類B來說不是最小接口,則類B和類D必須去實現他們不需要的方法。
解決方案
將臃腫的接口I拆分為獨立的幾個接口,類A和類C分別與他們需要的接口建立依賴關系。也就是采用接口隔離原則。
與單一職責原則區別
- 單一職責原則原注重的是職責;而接口隔離原則注重對接口依賴的隔離
- 單一職責原則主要是約束類,其次才是接口和方法,它針對的是程序中的實現和細節;而接口隔離原則主要約束接口接口,主要針對抽象,針對程序整體框架的構建
需注意
- 接口盡量小,但是要有限度。對接口進行細化可以提高程序設計靈活性,但是如果過小,則會造成接口數量過多,使設計復雜化。所以一定要適度
- 提高內聚,減少對外交互。使接口用最少的方法去完成最多的事情
- 為依賴接口的類定制服務。只暴露給調用的類它需要的方法,它不需要的方法則隱藏起來。只有專注地為一個模塊提供定制服務,才能建立最小的依賴關系。
6. 迪米特法則---只與直接的朋友通信
Law Of Demeter
:一個對象應該對其他對象保持最少的了解。
定義
一個類對自己依賴的類知道的越少越好。無論被依賴的類多么復雜,都應該將邏輯封裝在方法的內部,通過public方法提供給外部。這樣當被依賴的類變化時,才能最小的影響該類。
問題由來:類與類之間的關系越密切,耦合度越大,當一個類發生改變時,對另一個類的影響也越大。
解決方案
盡量降低類與類之間的耦合。
最少知道原則的另一個表達方式是:只與直接的朋友通信。類之間只要有耦合關系,就叫朋友關系。耦合分為依賴、關聯、聚合、組合等。我們稱出現為成員變量、方法參數、方法返回值中的類為直接朋友。局部變量、臨時變量則不是直接的朋友。我們要求陌生的類不要作為局部變量出現在類中。
參考文章
設計模式六大原則
23種設計模式匯總整理
設計模式原則