SOLID 物件導向程式設計的五個基本原則

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

一個類別應該只負責一件事情

  • 每個類別都應該專注於單一職責,若有其他需求,應透過協作方式使用其他類別,這樣可以提高程式碼的可重用性與模組化設計,並提升「內聚性」。
  • 當需要修改功能時,只需修改該職責對應的類別,降低模組間的耦合度,也方便維護與測試。

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

對擴展開放,對修改封閉

  • 軟體設計應具有彈性,當需求變更時,應透過「擴充」功能來應對,而不是直接修改既有類別。
  • 可將變動頻繁的附加邏輯模組化,並與主要邏輯透過抽象介面(interface)解耦。
  • 可利用依賴注入(Dependency Injection)將變動邏輯傳入,避免直接寫死在類別中。

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

子類別應該可以替代父類別而不影響程式正確性

  • 若某個物件使用父類別時能正常運作,使用其子類別也應該能保持相同行為。
  • 子類別不應強化「前置條件」;也不能弱化「後置條件」;應維持父類別的「不變條件」。
  • 此原則是契約式設計的基礎,違反會導致繼承架構無法正確運作。

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

不應強迫類別依賴其不使用的方法

  • 一個介面應該只包含使用者所需的方法,避免臃腫的介面導致實作類別產生空方法或不合理實作。
  • 將大介面拆分成多個小介面,每個小介面專注於特定功能。
  • 可透過「組合」取代「繼承」實現靈活設計。

範例:

<?php

// 不良設計:臃腫的介面
interface Worker {
    public function work();
    public function eat();
}

// 遵循ISP:拆分成多個小型介面
interface Workable {
    public function work();
}

interface Eatable {
    public function eat();
}

class HumanWorker implements Workable, Eatable {
    public function work() {
        // 人類工人工作
    }

    public function eat() {
        // 人類工人吃飯
    }
}

class RobotWorker implements Workable {
    public function work() {
        // 機器人工作
    }
    // 不需實作 Eatable
}
?>

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

高階模組不應依賴低階模組,兩者皆應依賴抽象

高階與低階模組定義

範例:

<?php

// 抽象資料來源介面
interface DataSource {
    public function connect();
    public function getData();
}

// 具體低階模組
class MySQLDatabase implements DataSource {
    public function connect() {
        // 連接 MySQL 資料庫
    }

    public function getData() {
        return "Data from MySQL";
    }
}

class ApiDataSource implements DataSource {
    public function connect() {
        // 連接 API
    }

    public function getData() {
        return "Data from API";
    }
}

// 高階模組:報表產生器
class SalesReportGenerator {
    private $dataSource;

    public function __construct(DataSource $dataSource) {
        $this->dataSource = $dataSource;
    }

    public function generate() {
        $this->dataSource->connect();
        $data = $this->dataSource->getData();
        echo "Generating report with data: " . $data;
    }
}

// 使用不同的資料來源
$mysql = new MySQLDatabase();
$reportGen = new SalesReportGenerator($mysql);
$reportGen->generate();

echo "\n";

$api = new ApiDataSource();
$reportGen = new SalesReportGenerator($api);
$reportGen->generate();
?>

結語

SOLID 原則為物件導向設計提供了堅實的基礎。善用這五項原則能讓系統更具模組化、易擴充、易維護與可測試性,是架構設計中的重要參考依據:

原則 縮寫 中文名稱 核心理念
Single Responsibility SRP 單一職責 每個類別只負責一個功能
Open/Closed OCP 開放封閉 對擴展開放,對修改封閉
Liskov Substitution LSP 里氏替換 子類別能替代父類別
Interface Segregation ISP 介面隔離 精簡且專一的介面
Dependency Inversion DIP 依賴反轉 依賴抽象,而非實作