1. 程式人生 > >設計模式分類以及六大設計原則(彙總篇)

設計模式分類以及六大設計原則(彙總篇)

設計模式的分類

建立型模式,共五種:

單例模式工廠方法模式抽象工廠模式建造者模式原型模式

結構型模式,共七種:

介面卡模式裝飾者模式代理模式門面模式(外觀模式)橋樑模式組合模式享元模式

行為型模式,共十一種:

策略模式模版方法模式觀察者模式迭代器模式責任鏈模式命令模式備忘錄模式狀態模式訪問者模式中介者模式直譯器模式

擴充套件模式:

規則模式物件池模式僱工模式黑板模式空物件模式

六大原則

總原則:開閉原則

定義:一個軟體實體如類、模組或函式應該對擴充套件開放,對修改關閉。

    簡單的說就是,當一個軟體實體需要擴充套件的時候,不要去修改原有的程式碼,而是去擴充套件原有的程式碼。其實開閉原則是最基礎的一個原則,下面六個原則都是開閉原則的具體形態。

為什麼要採用開閉原則:

  1. 對測試的影響:通過擴充套件實現變化,測試只需要對新增類進行單元測試即可,單元測試是孤立的,只需要保證新類提供的方法正確就行。而如果是修改類來實現變化,則該類相應的測試方法也都要隨著重構,而且當類很複雜時難免存在遺漏情況。
  2. 可以提高複用性:避免以後維護人員為了修改一個微小的缺陷或增加新功能,卻要在整個專案中到處查詢相關的程式碼逐一修改。
  3. 提高可維護性:開發新功能時,擴充套件一個類往往比修改一個類更容易。
  4. 面向物件開發的要求

1. 單一職責原則(Single Responsibility Principle,SRP)

定義:應該有且僅有一個原因引起類的變更。

優點:

  1. 類的複雜性降低。類的職責單一,複雜性自然就降低了。
  2. 可讀性高。
  3. 易維護。
  4. 變更引起的風險降低。

難點:

  1. “職責”和“變化原因”都是不可度量的,因專案、環境而異。
  2. 過細的劃分會引起類的劇增,人為的增加系統的複雜性。

建議:

  1. 介面的設計一定要做到單一原則,類的設計儘量做到只有一個原因引起變化。
  2. 職責的劃分需要根據專案和經驗來權衡,既要保證職責的單一性,又要儘量避免過細的劃分。

2. 里氏替換原則(Liskov Substitution Principle,LSP)

定義:所有引用基類的地方都必須能透明地使用其子類的物件。

繼承的優點:

  1. 程式碼共享,提高程式碼的重用性。
  2. 提高程式碼的可擴充套件性。
  3. 提高產品或者專案的開放性。

繼承的缺點:

  1. 繼承是侵入式的,只要繼承,就擁有了父類的屬性和方法。
  2. 降低程式碼靈活性,子類擁有了父類的屬性和方法,多了一些約束。
  3. 增強了耦合性。父類的常量、變數或方法改動時,必須還要考慮子類的修改,可能會有大段程式碼需要重構。

里氏替換原則四層含義:

  1. 子類必須完全實現父類的方法
    在類中呼叫其他類時務必使用父類或介面,如若不能,則說明類的設計已經違背LSP原則。
    如果子類不能完整的實現父類的方法,或者父類的方法在子類中發生畸變,這建議斷開父子繼承關係,採用依賴、聚集、組合等方式代替繼承。
  2. 子類可以有自己的特性:即子類出現的地方父類未必可以出現。
  3. 覆蓋父類的方法時輸入引數可以被放大:輸入引數型別寬於父類的型別的覆蓋範圍,例如 hashmap -> map。
  4. 覆蓋父類的方法時輸出引數可以被縮小

3. 依賴倒置原則(Dependence Inversion Principle,DIP)

定義:

  1. 高層模組不應該依賴低層模組,兩者都要改依賴其抽象(模組間的依賴通過抽象產生,實現類不發生直接的依賴關係)
  2. 抽象不應該依賴細節(介面或者抽象類不依賴實現類)
  3. 細節可以依賴抽象(實現類依賴介面或者抽象類)

建議:

  1. 每個類儘量都有介面或抽象類。
  2. 變數的表面型別儘量是介面或抽象類。
  3. 任何類都不應該從具體類派生(其實只要不是超過兩層的繼承都是可以忍受的)。
  4. 儘量不要複寫基類已實現的方法。
  5. 結合里氏替換原則使用。

面向介面程式設計:

    介面負責定義 public 屬性和方法,並且宣告與其它物件的依賴關係,抽象類負責公共構造部分的實現,實現類準確實現業務邏輯,同時在適當的時候對父類進行細化。

4. 介面隔離原則

定義:客戶端不應該依賴他不需要的介面,類之間的依賴關係應該建立在最小的介面上。

四層含義:

  1. 介面儘量要小,不要出現臃腫的介面。
  2. 介面要高內聚。
  3. 只提供訪問者需要的方法:每個介面中不存在子類用不到卻必須實現的方法,如果不然,就要將介面拆分。
  4. 介面設計是有限度的:介面設計粒度越小,系統越靈活。但是結構會越複雜、開發難度增加,可維護性降低。

建議:

  1. 一個介面只服務一個子模組或者業務邏輯。
  2. 儘量壓縮介面內的方法,保證方法都是有用的,避免臃腫。
  3. 已經被汙染的介面儘量去修改,若變更風險大,則採用介面卡模式轉化處理。
  4. 深入瞭解業務邏輯,拒絕盲從。

5. 迪克特法則(最少知道原則)(Least Knowledge Principle,LKP)

定義:一個物件應該對其他物件有最少的瞭解(低耦合)。

三層含義:

  1. 一個類只與朋友交流,不和陌生類交流,方法儘量不引入類中不存在的物件。
  2. 儘量不要對外暴露過多的 public 方法和非靜態的 public 變數,儘量內斂。
  3. 自己的就是自己的。如果一個方法放在本類中,既不增加類間關係,也對本類不產生負面影響,那就放置在本類中。

總結:
    迪米特法則的核心觀念就是類間解耦,低耦合。其負面影響就是產生了大量的中轉或者跳轉類,導致系統複雜性提高,也為維護帶來了難度。需要反覆權衡,既做到結構清晰,又要高內聚低耦合。
如果一個類需要跳轉兩次以上才能訪問到另一個類,就需要想辦法重構了。

6. 合成複用原則(Composite/Aggregate Reuse Principle,CARP)

定義:是在一個新的物件裡面使用一些已有的物件,使其成為新物件的一部分。新物件通過委派達到複用已有功能的效果。

優點:
    使用物件的合成/聚合將有助於你保持每個類被封裝,並被集中在單個任務上。這樣類和整合層次會保持較小規模,並且不太可能增長為不可控制的龐然大物。

缺點:
    通過這種方式複用建造的系統會有較多的物件需要管理;為了能將多個不同的物件作為組合塊來使用,必須仔細地對介面進行定義。

簡單地說:儘量首先使用合成/聚合的方式,而不是使用繼承。