iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
Software Development

軟體架構備忘錄系列 第 13

Day 13 程式架構 - SOLID原則 (知識點067~071)

  • 分享至 

  • xImage
  •  

思考的問題

設計物件導向程式時,有哪些需要注意的重要原則呢?

在物件導向的設計中,有許多經典的設計原則。其中最出名的就是SOLID原則。
其中分別為

  • S: 單一職責原則 (Single Responsibility Principle,SRP)
  • O: 開放封閉原則 (Open-Close Principle,OCP)
  • L: 里氏替換原則 (Liskov Substitution Principle,LSP)
  • I: 介面隔離原則 (Interface Segregation Principle,ISP)
  • D: 依賴反轉原則 (Dependency inversion principle,DIP)

單一職責原則

描述

此為程式設計與系統規劃的通用原則。
單一職責原則 (Single Responsibility Principle,SRP)指出任何一段程式,例如:類別、介面或函數應該只負責單一職責。

優點

  • 減少耦合度:由於程式只負責單一職責,降低了各程式之間的耦合度。可避免異動程式時,對其他程式造成影響。
  • 提高可讀性:程式僅負責單一職責,因此簡化程式的架構與邏輯,讓程式更易於理解。
  • 可維護性:低耦合度的程式中,新增或修改功能都較容易。
  • 可測試性:由於程式功能單純,因此較易撰寫單元測試,便於後續自動進行測試。

舉例

  • 在書籍訂單系統之中,訂單管理、訂單正確性檢查、操作訂單資料表 應分為不同的類別。

開放封閉原則

描述

這是對功能調整的原則。
開放封閉原則 (Open-Close Principle,OCP) 是指程式功能調整時,應該避免修改現有程式,而透過擴展程式來達到功能調整的目的。包含新增方法、類別、介面等方式都可以達到此目的。

優點

  • 減少修改幅度:由於只有擴增功能而非修改現有程式,這可避免現有依賴程式調整。

實現做法

  1. 繼承: 子類別可以在繼承父類別現有功能的情況下,針對差異的部分進行覆寫。實作介面也可以達到類似的作法。
  2. 多型: 同樣的一個方法,在不同傳入值的情況下,可有不同的實作。因此增加不同的傳入值,以處理不同的情況,以避免改變現有方法。
  3. Builder 建造者模式:提供彈性建立物件的方式
  4. Decortor 裝飾者模式:動態添加額外功能
  5. 依賴注入模式:將變動的邏輯抽成獨立的介面,依照傳入的介面實作不同,而有不同的處理邏輯。

里氏替換原則

描述

此為繼承時的設計原則。
里氏替換原則 (iskov Substitution Principle,LSP) 的概念為,子類別應該可以完全替換父類別的任何使用位置。子類別需要保持與父類別的行為一致,只是針對細節做出更多補充。如果真的需要不同的功能,代表應該分出不同的類別或新增不同的方法,而不在此父類別的繼承進行調整。

優點

  • 避免不一致的結果:由於其他程式並不需要知道此父類別程式的具體實作類別,當子類別的行為與父類別有衝突時,呼叫的程式可能會產生錯誤。

可替換父類別的前提

  • 行為模式需要與父類別一致
  • 只擴增該父類別的行為細節

舉例

  • 假設我們有一個介面名為「DataReader」,用於讀取不同類型的資料,例如從檔案、資料庫或網路中讀取。根據Liskov Substitution Principle,任何實作「DataReader」介面的類別應該能夠替代「DataReader」的使用,並且提供一致的行為。

介面隔離原則

描述

這是介面的設計原則。
介面隔離原則 (Interface Segregation Principle,ISP) 是指若某些情況下介面的某些功能不需要被實作時,應將該介面拆分為多個子介面。以避免一個類別強制實作不需要的方法,並提升程式的內聚性。

優點

  • 增進介面定義精細度:如果某些情況下,部分介面功能不需要實作,代表此介面涵蓋的範圍不夠明確。藉由拆分介面,以增進介面定義的細緻度。
  • 高內聚:由於介面的定義的顆粒度較低,這代表此介面功能高內聚。這可讓程式的可讀性和維護性提升。
  • 減少無意義的程式:類別由於無須實作未使用的方法,這減少了無意義的程式,也增加程式的可讀性。
  • 減少錯誤風險:由於不存在無實作的方法,可避免程式誤用。

舉例

舉個例子來說,假設有一個名為「DataManager」的介面,負責資料的查詢和修改。若有些情況下只需要實作查詢功能,那麼應該將「DataManager」介面拆分為「DataReader」和「DataModifier」兩個子介面。這樣,每個子類別可以根據具體需求獨立實作,提升彈性和可擴展性。


依賴反轉原則

描述

這是減少程式直接耦合的方式的原則。
依賴反轉原則 (Dependency inversion principle,DIP) 是指在開發高階功能時,避免在其中直接實例化具有不同實作內容的底層功能。實作高階功能時只需指定所需底層功能的介面,後續動態傳入此底層介面的具體實作。

優點

  • 避免程式調整:未來如果要抽換底層功能時,動態調整傳入的底層元件即可。
  • 提升高階功能使用範圍:可依據傳入底層元件的不同,滿足不同的應用情境的使用需求。

實現做法

  • 依賴注入:元件在設計時指定傳入的介面,當使用該元件時,透過傳入的介面實作來動態決定該元件的功能實現方式。
  • 依賴尋找:利用像 Spring 這樣的容器管理機制,容器能夠在需要時動態配置所需介面的具體實作物件。

舉例

在高階功能中,需要進行商品清單的新增和修改操作。但是這些操作的具體實作方式可能有多種選擇,例如將資料寫入傳統資料庫、NoSQL資料庫,或者使用快取等方式。在這種情況下,不應該在高階功能中直接指定商品清單操作的具體實作類別。相反的,高階功能僅需參考商品清單操作的介面,並通過在建立高階功能物件時,以動態方式指定商品清單操作的具體實作方式。



上一篇
Day 12 系統架構 - Log分析與警示 (知識點062~066)
下一篇
Day 14 程式架構 - 創建型設計模式 (知識點072~075)
系列文
軟體架構備忘錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言