程式概念 - SOLID (物件導向設計)
| 2025-4-10
字數 1368閱讀時間 4 分鐘
SOLID 是5大原則的簡稱,分別為:
S
Single Responsibility Principle
單一職責原則
O
Open-closed Principle
開放封閉原則
L
Liskov Substitution Principle
里氏替換原則
I
Interface Segregation Principle
介面隔離原則
D
Dependency inversion Principle
依賴反向原則
 

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

💡
一個類別應該只有一個變更的原因,也就是說,每個類別應該只負責一件事。
為什麼這很重要?
如果一個類別負責太多事情,那麼當某個功能需要修改時,可能會影響其他無關的功能,增加錯誤發生的機率,降低程式的可維護性。
 
違反 SRP 的例子:
這裡的問題是OrderManager 負責三件事(業務邏輯、資料庫操作、通知系統),當你想修改通知系統時,可能會影響訂單處理的邏輯,這違反了 SRP。
 
如何改善?
可以拆分成不同的類別,各自負責不同的功能:
這樣,每個類別都有單一職責,變更時影響範圍更小,程式碼更容易維護。

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

💡
對擴展開放,對修改封閉。這意味著應該透過擴展(新增功能)來改變系統行為,而不是直接修改原始碼。
為什麼這很重要?
如果直接修改原始碼,可能會影響系統的穩定性,甚至造成新的 bug。因此,應該透過繼承策略模式來擴展功能,而不是直接改動既有的類別。
 
違反 OCP 的例子
假設我們有一個 DiscountService 負責計算折扣:
如果以後要新增聖誕節折扣,我們就得修改 DiscountService,這違反 OCP,因為我們修改了原始碼,這可能會影響其他功能。
 
如何改善?
我們可以使用多型來實現 OCP:
現在如果要新增聖誕節折扣,只需新增 ChristmasDiscount 類別,而不需要修改 DiscountService,這符合 OCP。

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

💡
子類別應該能夠替換父類別,而不影響程式運行。
為什麼這很重要?
如果某個子類別不能完全取代父類別,那麼在多型(Polymorphism)運行時可能會導致不預期的錯誤。
 
違反 LSP 的例子:
如果某個方法接受 Bird 類別,並預期它能飛,當傳入 Penguin 時就會發生錯誤,這違反了 LSP。
 
如何改善?
可以重構設計,讓 Bird 類別只包含所有鳥類共有的行為:
這樣 Penguin 不會繼承 fly() 方法,就不會有違反 LSP 的問題。

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

💡
不應該強迫類別實作它不需要的方法。應該拆分成多個小介面,而不是一個大介面。
 
違反 ISP 的例子
Printer 被強迫實作 scan()fax(),但它根本不需要。
 
如何改善?
拆分成更小的介面:
這樣,每個類別只實作它需要的功能。

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

💡
高層模組(業務邏輯)不應該直接依賴低層模組(具體實作),應該依賴抽象(介面)。
 
違反 DIP 的例子
這樣 OrderService 只能使用 MySQL,如果要改用 PostgreSQL,就得修改 OrderService
 
如何改善?
現在 OrderService 依賴 Database 介面,可以輕鬆切換不同的資料庫。
Loading...