設計模式分類以及六大設計原則(彙總篇)
設計模式的分類
建立型模式,共五種:
單例模式、工廠方法模式、抽象工廠模式、建造者模式、原型模式。
結構型模式,共七種:
介面卡模式、裝飾者模式、代理模式、門面模式(外觀模式)、橋樑模式、組合模式、享元模式。
行為型模式,共十一種:
策略模式、模版方法模式、觀察者模式、迭代器模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。
擴充套件模式:
六大原則
總原則:開閉原則
定義:一個軟體實體如類、模組或函式應該對擴充套件開放,對修改關閉。
簡單的說就是,當一個軟體實體需要擴充套件的時候,不要去修改原有的程式碼,而是去擴充套件原有的程式碼。其實開閉原則是最基礎的一個原則,下面六個原則都是開閉原則的具體形態。
為什麼要採用開閉原則:
- 對測試的影響:通過擴充套件實現變化,測試只需要對新增類進行單元測試即可,單元測試是孤立的,只需要保證新類提供的方法正確就行。而如果是修改類來實現變化,則該類相應的測試方法也都要隨著重構,而且當類很複雜時難免存在遺漏情況。
- 可以提高複用性:避免以後維護人員為了修改一個微小的缺陷或增加新功能,卻要在整個專案中到處查詢相關的程式碼逐一修改。
- 提高可維護性:開發新功能時,擴充套件一個類往往比修改一個類更容易。
- 面向物件開發的要求
1. 單一職責原則(Single Responsibility Principle,SRP)
定義:應該有且僅有一個原因引起類的變更。
優點:
- 類的複雜性降低。類的職責單一,複雜性自然就降低了。
- 可讀性高。
- 易維護。
- 變更引起的風險降低。
難點:
- “職責”和“變化原因”都是不可度量的,因專案、環境而異。
- 過細的劃分會引起類的劇增,人為的增加系統的複雜性。
建議:
- 介面的設計一定要做到單一原則,類的設計儘量做到只有一個原因引起變化。
- 職責的劃分需要根據專案和經驗來權衡,既要保證職責的單一性,又要儘量避免過細的劃分。
2. 里氏替換原則(Liskov Substitution Principle,LSP)
定義:所有引用基類的地方都必須能透明地使用其子類的物件。
繼承的優點:
- 程式碼共享,提高程式碼的重用性。
- 提高程式碼的可擴充套件性。
- 提高產品或者專案的開放性。
繼承的缺點:
- 繼承是侵入式的,只要繼承,就擁有了父類的屬性和方法。
- 降低程式碼靈活性,子類擁有了父類的屬性和方法,多了一些約束。
- 增強了耦合性。父類的常量、變數或方法改動時,必須還要考慮子類的修改,可能會有大段程式碼需要重構。
里氏替換原則四層含義:
- 子類必須完全實現父類的方法
在類中呼叫其他類時務必使用父類或介面,如若不能,則說明類的設計已經違背LSP原則。
如果子類不能完整的實現父類的方法,或者父類的方法在子類中發生畸變,這建議斷開父子繼承關係,採用依賴、聚集、組合等方式代替繼承。 - 子類可以有自己的特性:即子類出現的地方父類未必可以出現。
- 覆蓋父類的方法時輸入引數可以被放大:輸入引數型別寬於父類的型別的覆蓋範圍,例如 hashmap -> map。
- 覆蓋父類的方法時輸出引數可以被縮小
3. 依賴倒置原則(Dependence Inversion Principle,DIP)
定義:
- 高層模組不應該依賴低層模組,兩者都要改依賴其抽象(模組間的依賴通過抽象產生,實現類不發生直接的依賴關係)
- 抽象不應該依賴細節(介面或者抽象類不依賴實現類)
- 細節可以依賴抽象(實現類依賴介面或者抽象類)
建議:
- 每個類儘量都有介面或抽象類。
- 變數的表面型別儘量是介面或抽象類。
- 任何類都不應該從具體類派生(其實只要不是超過兩層的繼承都是可以忍受的)。
- 儘量不要複寫基類已實現的方法。
- 結合里氏替換原則使用。
面向介面程式設計:
介面負責定義 public 屬性和方法,並且宣告與其它物件的依賴關係,抽象類負責公共構造部分的實現,實現類準確實現業務邏輯,同時在適當的時候對父類進行細化。
4. 介面隔離原則
定義:客戶端不應該依賴他不需要的介面,類之間的依賴關係應該建立在最小的介面上。
四層含義:
- 介面儘量要小,不要出現臃腫的介面。
- 介面要高內聚。
- 只提供訪問者需要的方法:每個介面中不存在子類用不到卻必須實現的方法,如果不然,就要將介面拆分。
- 介面設計是有限度的:介面設計粒度越小,系統越靈活。但是結構會越複雜、開發難度增加,可維護性降低。
建議:
- 一個介面只服務一個子模組或者業務邏輯。
- 儘量壓縮介面內的方法,保證方法都是有用的,避免臃腫。
- 已經被汙染的介面儘量去修改,若變更風險大,則採用介面卡模式轉化處理。
- 深入瞭解業務邏輯,拒絕盲從。
5. 迪克特法則(最少知道原則)(Least Knowledge Principle,LKP)
定義:一個物件應該對其他物件有最少的瞭解(低耦合)。
三層含義:
- 一個類只與朋友交流,不和陌生類交流,方法儘量不引入類中不存在的物件。
- 儘量不要對外暴露過多的 public 方法和非靜態的 public 變數,儘量內斂。
- 自己的就是自己的。如果一個方法放在本類中,既不增加類間關係,也對本類不產生負面影響,那就放置在本類中。
總結:
迪米特法則的核心觀念就是類間解耦,低耦合。其負面影響就是產生了大量的中轉或者跳轉類,導致系統複雜性提高,也為維護帶來了難度。需要反覆權衡,既做到結構清晰,又要高內聚低耦合。
如果一個類需要跳轉兩次以上才能訪問到另一個類,就需要想辦法重構了。
6. 合成複用原則(Composite/Aggregate Reuse Principle,CARP)
定義:是在一個新的物件裡面使用一些已有的物件,使其成為新物件的一部分。新物件通過委派達到複用已有功能的效果。
優點:
使用物件的合成/聚合將有助於你保持每個類被封裝,並被集中在單個任務上。這樣類和整合層次會保持較小規模,並且不太可能增長為不可控制的龐然大物。
缺點:
通過這種方式複用建造的系統會有較多的物件需要管理;為了能將多個不同的物件作為組合塊來使用,必須仔細地對介面進行定義。
簡單地說:儘量首先使用合成/聚合的方式,而不是使用繼承。