首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 物件導程式設計實戰:以「日常生活」理解 Class 與 Interface 的差異

     編輯:PHP 相關知識

前言:為什麼要用生活例子理解 OOP?

物件導向程式設計(OOP)中的「類別」與「介面」是兩大核心支柱,但初學者常混淆兩者的使用時機。本文透過一個輕鬆幽默的「家庭分工」情境——定義「老婆」的角色與行為,來對比「繼承基類」與「實作介面」兩種設計模式的程式碼結構與思維差異。

情境設定:核心職責與個人興趣

  • 核心職責(共通契約):煮飯、買菜、洗衣服、做家務。
  • 個人行為(獨有功能):打遊戲、打籃球、看電視。

模式一:抽象基類繼承

此模式將共通邏輯(如煮飯流程:檢查食材→缺料買菜→烹飪)封裝在基類 Wife 中,子類 I 繼承並複寫特定方法。

<?php
/**
 * 基類:定義預設家務流程
 */
class Wife {
    public function Cook($howToCook, $vegetableArray) {
        $this->BuyVegetables($vegetableArray);
        foreach ($howToCook as $dish) {
            // 簡化邏輯:檢查食材是否備齊
            if (!in_array($dish['one'], $vegetableArray)) {
                $this->BuyVegetables([$dish['one']]);
            }
            if (!in_array($dish['two'], $vegetableArray)) {
                $this->BuyVegetables([$dish['two']]);
            }
            echo "烹飪:{$dish['operation']}{$dish['one']}{$dish['two']}<br>";
        }
    }

    public function BuyVegetables($vegetableArray) {
        echo "去菜市場採購:" . implode('、', $vegetableArray) . "<br>";
    }

    public function WashClothes() {
        echo "1. 干洗外套<br>2. 洗衣機洗褲子<br>3. 手洗襪子<br>";
    }

    public function DoHouseholdDuties() {
        echo "1. 掃地<br>2. 拖地<br>3. 擦桌子<br>";
    }
}

/**
 * 子類:繼承 Wife,複寫或擴充行為
 */
class I extends Wife {
    public function PlayGames() { echo "打遊戲<br>"; }
    public function PlayBasketball() { echo "打籃球<br>"; }
    public function WatchTV() { echo "看電視<br>"; }

    // 複寫煮飯方法:定義專屬菜單並呼叫父類流程
    public function Cook() {
        $menu = [
            ['one' => '豬肉', 'two' => '芹菜', 'operation' => '炒'],
            ['one' => '土豆', 'two' => '牛肉', 'operation' => '燒'],
        ];
        $stock = ['豬肉', '雞蛋', '酸奶', '香菇', '芹菜', '土豆', '牛肉'];
        parent::Cook($menu, $stock);
    }

    public function WashClothes() { parent::WashClothes(); }
    public function DoHouseholdDuties() { parent::DoHouseholdDuties(); }
}

// 使用範例
$me = new I();
$me->Cook();
$me->PlayGames();
?>

特點:I 自動擁有 Wife 的所有預設實作,適合「是一種」關係且需共享大量預設邏輯的場景。但耦合度較高,子類受限於父類結構。

模式二:介面實作

介面 Wife 僅定義「必須做什麼」(方法簽章),不提供任何實作。類別 I 實作介面,必須自行撰寫所有方法邏輯。

<?php
/**
 * 介面:定義契約,不含實作
 */
interface Wife {
    public function Cook($howToCook, $vegetableArray);
    public function BuyVegetables($vegetableArray);
    public function WashClothes();
    public function DoHouseholdDuties();
}

/**
 * 實作類別:完全自訂邏輯
 */
class I implements Wife {
    public function PlayGames() { echo "打遊戲<br>"; }
    public function PlayBasketball() { echo "打籃球<br>"; }
    public function WatchTV() { echo "看電視<br>"; }

    public function Cook($howToCook, $vegetableArray) {
        $this->BuyVegetables($vegetableArray);
        foreach ($howToCook as $dish) {
            if (!in_array($dish['one'], $vegetableArray)) {
                $this->BuyVegetables([$dish['one']]);
            }
            if (!in_array($dish['two'], $vegetableArray)) {
                $this->BuyVegetables([$dish['two']]);
            }
            echo "烹飪:{$dish['operation']}{$dish['one']}{$dish['two']}<br>";
        }
    }

    public function BuyVegetables($vegetableArray) {
        echo "去菜市場採購:" . implode('、', $vegetableArray) . "<br>";
    }

    public function WashClothes() {
        echo "1. 干洗外套<br>2. 洗衣機洗褲子<br>3. 手洗襪子<br>";
    }

    public function DoHouseholdDuties() {
        echo "1. 掃地<br>2. 拖地<br>3. 擦桌子<br>";
    }
}

// 使用範例(介面型別宣告,利於多型)
$me = new I();
$me->Cook([
    ['one' => '豬肉', 'two' => '芹菜', 'operation' => '炒'],
    ['one' => '土豆', 'two' => '牛肉', 'operation' => '燒'],
], ['豬肉', '雞蛋', '酸奶', '香菇', '芹菜', '土豆', '牛肉']);
?>

特點:I 擁有完全自主權,可依需求調整演算法細節。介面可被多個類別實作(如 Husband, Robot),支援「依賴倒置」與單元測試 Mock,架構彈性極高。

核心差異總結比較表

比較維度抽象基類繼承介面實作
關係語意Is-a (是一種)Can-do (能做某事)
程式碼重用高(繼承父類邏輯)低(需自行實作)
耦合程度緊密(父類變動影響子類)鬆散(僅綁定契約)
多型支援單一繼承鏈可實作多個介面
適用場景核心邏輯穩定、共享度高需多樣化實作、強調解耦

最佳實務建議

  1. 優先使用介面:定義服務契約(如 PaymentGatewayInterface),實作類別專注業務邏輯。
  2. 抽象類輔助:當多個實作有大量共同預設行為(如資料庫連線、日誌格式),建立 AbstractBase 供繼承,減少重複代碼。
  3. 組合大於繼承:若 I 需要「會煮飯」與「會洗衣」兩種能力,考慮注入 CookingService、LaundryService 物件,而非硬性繼承單一基類。

結語

透過「家庭分工」這個生活化隱喻,我們清楚看到:繼承是為了重用「實作」,介面是為了定義「契約」。實務開發中,靈活運用兩者,配合組合模式,才能打造出高內聚、低耦合、易維護的 PHP 應用架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved