SOLID 筆記

本篇僅紀錄自己學習SOLID的內容摘要,會依照自己的理解和書中的內容結合後將內容打上
如果有理解錯誤的地方,可以在下面的 gitalk 留言通知我

SOLID原則

SOLID 原則是為了鞏固軟體的架構而存在的原則,目的是要減少程式之間的耦合,方便程式的維護與擴充

SOLID 本身是由五種原則所構成,分別為:

  • 單一職責原則 (SRP : Single-Responsibility Principle)
  • 開放封閉原則 (OCP : Open-Closed Principle)
  • 里氏替換原則 (LSP : Liskov Subtitution Principle)
  • 介面隔離原則 (ISP : Interface Segregation Principle)
  • 依賴反轉原則 (DIP : Dependency-Inversion Principle)

S - 單一職責原則 (SRP : Single-Responsibility Principle)

一個類別應該只有一個發生變化的原因
  • 一個類別應該只會有一個職責在身,不應該含有多個職責
  • 當發生變化時,這個類別的其他職責不應該受到變化的職責的影響

所以任何一個符合 SRP 的類別都將只會處理一項業務,不應該同時包含兩種業務在內

每一個類別和其底下的函式都只會受到所關注的業務變化影響而改變關注的業務細節,並不會影響到其他業務

舉一個違反 SRP 的函式例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public List<User> SearchUser(List<User> users, int userid, string username) {
List<User> matches = new List<User>();
foreach (User user : users) {
if (userid != -1 && user.Id == userid) {
if (!string.IsNullOrEmpty(username) && user.Name == username) {
matches.Add(user);
}
}
if (!string.IsNullOrEmpty(username) && user.Name == username) {
if (userid != -1 && user.Id == userid) {
matches.Add(user);
}
}
}
}

這邊將搜尋 ID 和名子的功能混在一起,不論是要新增條件或是刪除條件,都會受到其他搜尋條件的影響

O - 開放封閉原則 (OCP : Open-Closed Principle)

軟體實體(類別、模組、函式等等)應該是可擴展的,但不可更改

軟體的實體都會透過介面去公開,而內部則不會變動,若有新的需求或變化,只需要實做一個符合介面的類別出來即可,這使得軟體易於擴展,卻不用重新部屬所有的二進制檔或 DLL 檔

L - 里氏替換原則 (LSP : Liskov Subtitution Principle)

子型態(subtype)必須能夠替換掉它們的基底型態(base type)

當兩個類別之間有繼承的關係時,子類別應該要能夠代替父類別

由於子類別是由父類別衍生出來的,因此它應該只會擴展父類別而不是改變父類別

若是子類別不能夠替換父類別,這表示他們的性質並不相同,則可以透過提取相似的性質作為介面將他們的「垂直關係」轉為「平行關係」

I - 介面隔離原則 (ISP : Interface Segregation Principle)

不應該強迫客戶程式依賴於它們未使用的方法

若是部份的客戶有特殊的需求,則不應該直接修改他們所使用到的介面,而應該另外產生一個專屬的介面

如果為了部份有特殊需求的客戶而修改原有的介面,這會導致本來不會受到影響的客戶也跟著受到了影響,他們也將要重新部屬他們的程式,僅僅只為了他們沒有需要用到的函式

因此若不確定所有的人都會有同樣的需求,則客製化一個介面會比直接修改原有的介面來得好

D - 依賴反轉原則 (DIP : Dependency-Inversion Principle)

a. 高層模組不應該依賴於(相依於)低層模組。二者都應該依賴抽象
b. 抽象不應該依賴細節。細節應該依賴抽象

低層的模組應該透過介面公開,而高層模組則使用介面,使得低層模組與高層模組都只依賴於抽象的介面

抽象的元件不應該依賴於有實做細節的元件,反而是實做細節的元件要依賴於抽象

透過介面做隔離使得模組之間的耦合降低,由於都只依賴於介面,因此當模組內部產生變化時,並不需要連同關聯的模組一起進行部屬,只要關注在產生變化的模組即可

同時,由於高層模組只依賴於介面,這使得高層模組可以依照需求產生新的低層模組進行擴充,而不會動到原先高層模組的結構

心得

從上面的五個原則中可以發現,SOLID 是為了方便程式的開發,減少修改程式碼的時間,減少程式部屬的時間而產生的原則,而且絕大多數都和「介面」有關,其最重要的核心理念在於「去除耦合」以及「增加元件的凝聚度」,這使得軟體中的每一個元件大都可以單獨被抽出來使用,不僅方便維修,也方便進行擴充工作,使得體的結構變得更加堅固,以應對源源不絕的需求與變化

由於我目前只是 SOLID 的初學者,還沒有比較豐富的重構經驗,因此也很難為這些原則提出適當的舉例,所以可以發現上面大多都是文字,如果之後對 SOLID 比較熟悉,我會再為每個原則開一篇文章出來講

參考

  • 無暇的程式碼—敏捷完整篇,物件導向原則、設計模式與 C# 實踐。