SOLID 原則是什麼?為什麼專業工程師一定要懂?

 SOLID 是物件導向設計中最重要的五大設計原則,由 Robert C. Martin(Uncle Bob)提出,目的在於:

讓系統更容易維護、擴充、測試,並降低長期技術債。

SOLID = 五個原則的縮寫:

字母 原則 全名
S SRP Single Responsibility Principle(單一職責原則)
O OCP Open/Closed Principle(開放封閉原則)
L LSP Liskov Substitution Principle(里氏替換原則)
I ISP Interface Segregation Principle(介面隔離原則)
D DIP Dependency Inversion Principle(依賴反轉原則)

S — Single Responsibility Principle(單一職責原則)

定義

一個類別應該只有一個改變的理由。

❌ 違反 SRP(壞例子)

public class OrderService { public void CreateOrder() { // 建立訂單 } public void SaveToDatabase() { // 存資料庫 } public void SendEmail() { // 寄送通知信 } }

問題

  • 商業邏輯

  • 資料存取

  • 通知機制

全部混在一起,任何一個需求變動都可能影響整個類別


✅ 符合 SRP(好例子)

public class OrderService { public void CreateOrder() { // 建立訂單 } } public class OrderRepository { public void Save() { // 存資料庫 } } public class EmailService { public void Send() { // 寄送通知信 } }

好處

✅ 類別職責清楚
✅ 改動風險小
✅ 更容易測試與維護


O — Open/Closed Principle(開放封閉原則)

定義

對擴充開放,對修改封閉。

❌ 違反 OCP

public decimal CalculateDiscount(string customerType) { if (customerType == "VIP") return 0.2m; if (customerType == "Normal") return 0.1m; return 0; }

問題

每加一種客戶 → 就要修改原本程式
➡ 容易引入 Bug


✅ 符合 OCP

public interface IDiscountStrategy { decimal GetDiscount(); } public class VipDiscount : IDiscountStrategy { public decimal GetDiscount() => 0.2m; } public class NormalDiscount : IDiscountStrategy { public decimal GetDiscount() => 0.1m; }
public decimal CalculateDiscount(IDiscountStrategy strategy) { return strategy.GetDiscount(); }

好處

✅ 新功能用「新增類別」
✅ 不用修改舊邏輯
✅ 減少回歸風險


L — Liskov Substitution Principle(里氏替換原則)

定義

子類別必須能夠替換父類別而不破壞程式正確性。

❌ 違反 LSP(經典例子)

public class Bird { public virtual void Fly() { } } public class Penguin : Bird { public override void Fly() { throw new NotSupportedException(); } }

問題

Penguin 是 Bird,但不會飛
➡ 破壞多型的信任


✅ 符合 LSP

public abstract class Bird { } public interface IFlyable { void Fly(); } public class Sparrow : Bird, IFlyable { public void Fly() { } } public class Penguin : Bird { // 不實作 Fly }

好處

✅ 多型更安全
✅ 設計更貼近真實模型


I — Interface Segregation Principle(介面隔離原則)

定義

不應強迫類別實作它不需要的方法。

❌ 違反 ISP

public interface IMachine { void Print(); void Scan(); void Fax(); }
public class OldPrinter : IMachine { public void Print() { } public void Scan() { throw new NotImplementedException(); } public void Fax() { throw new NotImplementedException(); } }

✅ 符合 ISP

public interface IPrinter { void Print(); } public interface IScanner { void Scan(); }

好處

✅ 類別更乾淨
✅ 減少無意義實作


D — Dependency Inversion Principle(依賴反轉原則)

定義

高層模組不應依賴低層模組,兩者都應依賴抽象。

❌ 違反 DIP

public class OrderService { private SqlOrderRepository _repo = new SqlOrderRepository(); public void Save() { _repo.Save(); } }

問題

  • 強耦合

  • 無法替換

  • 難以單元測試


✅ 符合 DIP(搭配 DI)

public interface IOrderRepository { void Save(); } public class SqlOrderRepository : IOrderRepository { public void Save() { } } public class OrderService { private readonly IOrderRepository _repo; public OrderService(IOrderRepository repo) { _repo = repo; } public void Save() { _repo.Save(); } }

違反 SOLID vs 遵守 SOLID 的整體差異

面向 違反 SOLID 遵守 SOLID
維護成本
擴充功能 容易改壞既有程式 安全新增功能,不影響既有邏輯
單元測試 困難(強耦合、難 Mock) 容易(可替換依賴、好 Mock)
重構風險 高(牽一髮動全身) 低(模組化、影響範圍小)
技術債 快速累積 可控、成長較慢
團隊協作 容易互相踩雷、修改衝突多 責任清楚、衝突較少
系統壽命 短期可用,長期難以維護 適合長期演進與持續擴充



為什麼資深工程師花很多時間在 Review 而不是一直寫新功能?

這點其實跟你之前問的 Code Review 很呼應:

資深工程師的價值不只是「寫更多程式」,而是:

✅ 確保架構符合 SOLID
✅ 避免技術債
✅ 提前阻止糟糕設計進主幹
✅ 讓團隊未來 1~2 年都好維護


結論(適合部落格收尾)

SOLID 不是為了「寫得比較漂亮」,而是為了:

降低變更成本,讓系統可以長期演進而不崩壞。

短期看起來多寫幾個 class,
長期會讓你少修很多 bug、少加很多班。

留言

熱門文章