再讀整潔架構之道(三)SOLID 設計原則

Tommy Cheese | · 閱讀約需 3 分鐘

再讀整潔架構之道(三)SOLID原則

構建軟體模組的主要目標有三個:

  • 使軟體可容忍被改動
  • 使軟體更容易被理解
  • 構建可在多個軟體系統中複用的元件

SOLID原則的主要作用就是告訴我們如何將資料和函式組織成為類,以及如何將這些類連結起來成為程式。SOLID原則指導我們如何設計模組,在架構設計層面,我們會有其他的設計原則。

SOLID原則是指單一職責原則SRP、開閉原則OCP、裡式替換原則LSP、介面隔離原則ISP和介面反轉DIP。

單一職責原則SRP

SRP定義每個軟體模組只對一個功能負責,只有一個理由可以讓模組改變,任何一個軟體模組都應該只對某一類行為者負責。

元件層面的SRP被稱作共同閉包原則CCP。

倘若設計模組時沒有遵循SRP會發生什麼呢?一起看一個例子。

如果財務部門、人事部門、研發部門共同依賴於一個工資、工時計算的程式,程式包含三個函式:

  • CalculateSalary:計算工資;
  • CalculateTime:計算工時;
  • Save:儲存資訊;

三個部門平靜地使用著程式,突然有一天,財務部的薪資計算發生變化,因此財務部門的維護人員更改了CalculateSalary函式;然後,詭異的事情發生了,人事部門、研發部薪資也同時變化了…

開閉原則OCP

“擁抱新增、抗拒修改!”

OCP指出:如果軟體系統想要更容易被改變,那麼其設計就必須允許新增程式碼來修改系統行為,而非只能靠修改原來的程式碼。設計良好的計算機軟體應該易於擴充套件,同時抗拒修改。

OCP不僅適用於類和模組的設計,也適用於元件的設計。他起源於裝置無關性的概念。具體來說,我們使用依賴反轉將IO裝置設計成外掛,這樣的我們就能很輕易的新增IO裝置,而不去修改原有的IO裝置。

OCP的實現方式是通過將系統劃分為一系列元件,並且將這些元件間的依賴關係按層次結構進行組織,使得高階元件不會因低階元件被修改而受到影響。

裡式替換LSP原則

LSP指出:如果想用可替換的元件來構建軟體系統,那麼這些元件就必須遵守同一個約定,以便讓這些元件可以相互替換。

LSP的本質是一個可替換性原則:如果對於每個型別是S的物件o1都存在一個型別為T的物件o2,能使操作T型別的程式P在用o1替換o2時行為保持不變,我們就可以將S稱為T的子型別。

LSP可以且應該被應用於軟體架構層面,因為一旦違背了可替換性,該系統架構就不得不為此增添大量複雜的應對機制。

介面隔離原則ISP

ISP指出:應該在設計中避免不必要的依賴,任何層次的軟體設計如果依賴了它並不需要的東西,就會帶來意料之外的麻煩。

依賴反轉DIP

DIP指出該設計原則指出高層策略性的程式碼不應該依賴實現底層細節的程式碼,恰恰相反,那些實現底層細節的程式碼應該依賴高層策略性的程式碼。

通俗理解依賴反轉:這需要使用控制流和原始碼依賴流來說明。控制流譬如A元件流向B元件,此時B需要知道A的實現,A也需要引入B的模組,程式碼依賴上也就不可避免的A元件流向了B元件。此時系統行為決定了控制流,而控制流則決定了原始碼依賴關係,軟體架構就別無選擇。但是通過引入介面,B元件此時只需要實現介面,介面引入B,A引入介面,此時A就無需引入B模組,此時的控制流和原始碼依賴是反向的,也就是“依賴反轉”。

依賴反轉給了軟體架構設計的自由,如果想要設計一個靈活的系統,在原始碼層次的依賴關係中就應該多引用抽象型別(介面、抽象類等),而非具體實現。

DIP可以歸納出幾條編碼守則:

  • 應在程式碼中多使用抽象介面,儘量避免使用那些多變的具體實現類;
  • 不要在具體實現類上建立衍生類;
  • 不要覆蓋(override)包含具體實現的函式;
  • 應避免在程式碼中寫入與任何具體實現相關的名字,或者是其他容易變動的事物的名字。

(第三篇完)

comments powered by Disqus