1. 程式人生 > 其它 >設計模式六大原則(翻譯)

設計模式六大原則(翻譯)

 

六大原則:

原文連結:https://medium.com/@mena.meseha/6-principles-of-software-design-3a8478954e1c

1 單一職責原則:

定義:

單一職責原則,也被稱為單一功能原則。就是說,使類變化的原因不超過一個。通俗地講,一個類只負責一個功能。

原則:

      如果一個類有太多的功能,也就是說有很多功能都聚合到一起,一個功能的改變可能弱化類的其他功能。

這種耦合會導致脆弱的設計,當變化發生時,設計會遭受意外的破壞。如果想避免這種情況的發生,

應該儘可能地遵循單一職責的原則。這個原則的核心是解耦和加強內聚。

 問題的起源:

       類T負責兩個不同的職責:職責P1,職責P2。當類T由於職責P1需要修改時,可能會導致原本正常執行的P2功能出現故障。

也就是說,職責P1和P2是耦合在一起的。

原因:

       程式設計師都知道應該編寫出高內聚低耦合的程式,但是很多耦合經常在不經意間發生,因為職責分散。

解決方案:

       一個類或者模組只負責一個功能。

優點:

  • 可以降低類的複雜性。一個類只負責一個功能,其邏輯肯定比負責多個功能簡單得多;
  • 提高類的可讀性,提高系統的可維護性;
  • 變更帶來的風險降低了,變更是不可避免的。
  • 如果很好地遵循單一職責原則,在修改一個功能時,可以顯著減少對其他功能的影響。

2 里氏替換原則(LSP):

定義:

面向物件設計的基本原則之一,任何基類出現的地方都可以被子類替換。

LSP 是繼承和重用的基礎。只有派生類可以替代基類,不影響軟體單元的功能,才能真正複用基類,

派生類也可以在基類的基礎上增加新的行為。即如果父類是功能模組的一部分,則使用子類代替父類,功能模組可以正常執行,子類例項也可以代替父類例項

 繼承的意思是,父類中已經實現的所有方法(相對於抽象方法),實際上都是在設定一系列的規範和約定,

雖然沒有強制要求所有的子類都必須遵循這些契約,但是如果子類隨意修改這些非抽象的方法,會對整個繼承系統造成破壞。

這就是里氏替換原則。

繼承作為面向物件的三大特性之一,給程式設計帶來了極大的便利,但也帶來了弊端。

例如,使用繼承會給程式帶來入侵,降低程式的可移植性,增加物件之間的耦合。

如果一個類被其他類繼承,則需要修改該類時必須考慮所有子類、類,以及修改父類後,所有涉及子類的函式都可能會失敗。

實際情況: 

在實際程式設計中,我們經常通過重寫父類的方法來完成新的功能,這樣雖然寫起來簡單,但是整個繼承系統的複用性會很差,

尤其是多型使用比較頻繁的時候。執行錯誤的機率非常高。 如果要覆蓋父類的方法,

比較常見的做法是: 原來的父類和子類繼承一個比較通用的基類,取消原來的繼承關係,改為使用依賴、聚合、組合等關係。

總結:

子類可以擴充套件父類的功能,但不能擴充套件父類的原有功能。

  • 子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法。
  • 子類可以新增自己獨特的方法。
  • 當子類的方法覆蓋父類的方法時,該方法的前提條件(即方法的形參)比父類的輸入引數更寬鬆。
  • 當子類的方法實現了父類的抽象方法時,方法的後置條件(即方法的返回值)比父類更嚴格。

 

3 依賴倒轉原則:

定義:

  上層模組不應該依賴下層模組,上層和下層模組都應該依賴它們的抽象;抽象不應該依賴於細節;細節應該依賴於抽象。

區別:

  對於面向過程的開發,上層呼叫下層,上層依賴下層。當下層發生劇烈變化時,上層也需要發生變化,導致模組的複用性降低,大大增加了開發成本。
面向物件的開發很好地解決了這個問題。一般來說,抽象變化的概率很小,使用者程式依賴於抽象,實現細節依賴於抽象。即使實現細節不斷變化,

只要抽象不改變,客戶端程式也不需要改變。這大大降低了客戶端程式和實現細節之間的耦合。

問題的根源:

A類直接依賴B類,如果要將A類改成依賴C類,必須通過修改A類的程式碼來實現。 這種場景下,A類一般是負責複雜業務邏輯的高層模組;

B 類和 C 類是負責基本原子操作的低階模組;如果修改A類,會給程式帶來不必要的風險。

解決方案:

修改A類依賴介面I。B類和C類各自實現介面I。A類通過介面I間接與B類或C類通訊,大大減少了修改A類的機會。

依賴倒置的原理是基於這樣一個事實,即抽象事物(介面或抽象類)比細節的可變性要穩定得多。建立在抽象上的架構比建立在細節(特定的實現類)上的架構要穩定得多。

傳遞依賴的方式有介面傳遞、建構函式傳遞、設定方法傳遞三種方式

編碼要求:

  • 低階模組應該有抽象類或介面,或者兩者都有。
  • 變數的宣告型別儘可能是抽象類或介面。
  • 使用繼承時遵循里氏置換原則。

 

4 介面隔離原則ISP

定義:

  客戶端不應依賴它不需要的介面;一個類對另一個類的依賴性應基於最小的介面。

問題的根源:

  A 類通過介面 I 依賴於類 B,C 類通過介面 I 依賴於 D 類。如果介面 I 不是類 A 和類 B 的最小介面,則類 B 和類 D 必須實現它們不需要的方法。

解決方案:

  將臃腫的介面 I 拆分為單獨的介面,A 類和 C 類分別與它們所需的介面建立依賴關係,介面隔離原理。

因此:

  建立單一的介面,不要構建大而臃腫的介面,儘量細化介面,介面中的方法儘可能小。也就是說,我們需要為每個類建立一個專用介面,而不是嘗試為依賴於它的所有類構建一個非常大的介面。

注意:

  • 介面功能儘可能少,細化介面可以提高程式設計的靈活性,但如果介面太小,它會導致太多的介面並使設計複雜化,所以一定要適度。
  • 為依賴於介面的類自定義服務僅向呼叫類公開它需要的方法,並且它不需要的方法被隱藏。只有專注於為模組提供自定義服務,才能建立最小的依賴關係。
  • 提高凝聚力並減少外部互動,使介面用最少的方法做最多的事情。

5. 最小知道原則

  這意味著一個物體應該對其他物體有儘可能少的知識,並且不與陌生人交談,英語縮寫為:LOD。

通俗地說,一個類對它所依賴的類瞭解得越少越好。也就是說,對於依賴類,無論邏輯多麼複雜,邏輯都儘可能地封裝在類中,外部提供的公共方法不會洩露任何資訊。另一種說法:只與直接的朋友溝通

直接朋友:

成員變數中的類、方法引數、方法返回值、

間接朋友:

區域性變數中的類

問題的根源:

類與類之間的關係越密切,耦合程度越高。當一個類更改時,對另一個類的影響更大。

解決方法:

嘗試減少類和類之間的耦合。

注意:

迪米特定律的初衷是減少類之間的耦合。由於每個類都減少了不必要的依賴關係,

因此它確實可以減少耦合關係。但凡事都有一定程度的,雖然可以避免與間接類的交流,但要進行交流,勢必要通過"中介"來連線。

過度使用Dimit原則將導致大量此類中介和交付類,從而導致系統複雜性增加。

因此,在使用Dimitte規則時,我們必須反覆權衡天平,使結構清晰,同時又具有高內聚性和低耦合性。

 

6. 開-閉原理

軟體實體(如類、模組和函式)應開放給擴充套件,不開放給修改。

問題的根源:

在軟體生命週期中,當軟體的原始程式碼由於更改、升級和維護而需要修改時,可能會在舊程式碼中引入錯誤,或者可能導致我們重構整個功能。存在已重新測試的程式碼。

解決方法:

當需要更改時,請嘗試通過擴充套件來實現更改,而不是修改現有程式碼來實現更改。

總結一下:

使用抽象生成框架通過實現擴充套件詳細資訊。 因為抽象的靈活性好,適應性廣,只要抽象合理,軟體架構基本可以保持穩定。

而軟體中的變數細節,我們用抽象派生的實現類來擴充套件,當軟體需要改變的時候,我們只需要重新派生一個實現類來根據需求進行擴充套件。

當然,前提是我們的抽象應該是合理的,我們必須前瞻性地預測需求的變化。