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

PHP 裝飾器模式實戰:動態組合職責、替代繼承爆炸的優雅方案

     編輯:PHP 相關知識

PHP 裝飾器模式實戰:動態組合職責、替代繼承爆炸的優雅方案

裝飾器模式以組合替代繼承,在不修改原類代碼的前提下,動態為對象添加新行為。它解決「繼承爆炸」問題:若有 3 種武器 × 4 種屬性,繼承需 12 個子類,裝飾器只需 3 + 4 = 7 個類。本文通過「武器+屬性」經典案例,展示標準結構、動態疊加、Laravel 中間件實踐與最佳原則。

一、核心結構:抽象組件 + 具體組件 + 抽象裝飾器 + 具體裝飾器

<?php
// 1. 抽象組件介面
interface Weapon {
    public function getDescription(): string;
    public function getCost(): float;
}

// 2. 具體組件:基礎武器
class Glave implements Weapon {
    public function getDescription(): string { return '長劍'; }
    public function getCost(): float { return 100.0; }
}

class Knife implements Weapon {
    public function getDescription(): string { return '匕首'; }
    public function getCost(): float { return 80.0; }
}

class Axe implements Weapon {
    public function getDescription(): string { return '斧頭'; }
    public function getCost(): float { return 200.0; }
}

// 3. 抽象裝飾器:持有組件引用,轉發調用
abstract class WeaponDecorator implements Weapon {
    protected Weapon $weapon;

    public function __construct(Weapon $weapon) {
        $this->weapon = $weapon;
    }

    // 默認轉發(具體裝飾器可選擇性覆蓋)
    public function getDescription(): string { return $this->weapon->getDescription(); }
    public function getCost(): float { return $this->weapon->getCost(); }
}

// 4. 具體裝飾器:屬性附魔
class Strength extends WeaponDecorator {
    public function getDescription(): string { return $this->weapon->getDescription() . ' +力量'; }
    public function getCost(): float { return $this->weapon->getCost() + 30.0; }
}

class Agility extends WeaponDecorator {
    public function getDescription(): string { return $this->weapon->getDescription() . ' +敏捷'; }
    public function getCost(): float { return $this->weapon->getCost() + 50.0; }
}

class Intellect extends WeaponDecorator {
    public function getDescription(): string { return $this->weapon->getDescription() . ' +智力'; }
    public function getCost(): float { return $this->weapon->getCost() + 20.0; }
}

// 5. 附魔:鑲嵌寶石(展示多層裝飾)
class GemSocket extends WeaponDecorator {
    private string $gemType;
    private float $bonus;

    public function __construct(Weapon $weapon, string $gemType, float $bonus) {
        parent::__construct($weapon);
        $this->gemType = $gemType;
        $this->bonus = $bonus;
    }

    public function getDescription(): string { return $this->weapon->getDescription() . " +{$this->gemType}(+{$this->bonus})"; }
    public function getCost(): float { return $this->weapon->getCost() + $this->bonus; }
}

二、動態組合示例

<?php
// 基礎武器
$weapon = new Glave(); // 長劍 100

// 疊加屬性:力量 + 力量 + 敏捷
$weapon = new Agility(
    new Strength(
        new Strength($weapon)
    )
);

echo $weapon->getDescription(); // 長劍 +力量 +力量 +敏捷
echo $weapon->getCost();        // 100 + 30 + 30 + 50 = 210

// 多層裝飾:武器 → 力量 → 寶石 → 敏捷 → 寶石
$weapon2 = new GemSocket(
    new Agility(
        new GemSocket(
            new Strength(new Knife()),
            '紅寶石', 100
        ),
        '藍寶石', 80
    )
);

echo $weapon2->getDescription(); // 匕首 +力量 +紅寶石(+100) +敏捷 +藍寶石(+80)
echo $weapon2->getCost();        // 80 + 30 + 100 + 50 + 80 = 340

三、進階:裝飾器鏈與條件裝飾

<?php
// 條件裝飾器:僅當滿足條件時添加行為
class ConditionalDecorator extends WeaponDecorator {
    private callable $condition;
    private WeaponDecorator $decorator;

    public function __construct(Weapon $weapon, callable $condition, WeaponDecorator $decorator) {
        parent::__construct($weapon);
        $this->condition = $condition;
        $this->decorator = $decorator;
    }

    public function getDescription(): string {
        return ($this->condition)($this->weapon) ? $this->decorator->getDescription() : $this->weapon->getDescription();
    }

    public function getCost(): float {
        return ($this->condition)($this->weapon) ? $this->decorator->getCost() : $this->weapon->getCost();
    }
}

// 使用:僅當武器基礎價值 > 150 時添加「神聖祝福」
$weapon = new ConditionalDecorator(
    new Axe(),
    fn(Weapon $w) => $w->getCost() > 150,
    new class(new Axe()) extends WeaponDecorator { // 匿名裝飾器
        public function getDescription(): string { return parent::getDescription() . ' +神聖祝福'; }
        public function getCost(): float { return parent::getCost() + 200; }
    }
);

四、Laravel 中間件:裝飾器模式的大規模實戰

Laravel HTTP 內核將請求處理封裝為中間件鏈,本質是裝飾器模式:

<?php
// 核心契約
interface HttpKernel {
    public function handle(Request $request): Response;
}

// 基礎應用(核心組件)
class Application implements HttpKernel {
    public function handle(Request $request): Response {
        // 路由分發、控制器執行、視圖渲染...
        return new Response('Hello World');
    }
}

// 中間件基類(抽象裝飾器)
abstract class Middleware implements HttpKernel {
    protected HttpKernel $next;

    public function __construct(HttpKernel $next) {
        $this->next = $next;
    }

    public function handle(Request $request): Response {
        // 前置邏輯
        $response = $this->next->handle($request);
        // 後置邏輯
        return $response;
    }
}

// 具體中間件(具體裝飾器)
class AuthMiddleware extends Middleware {
    public function handle(Request $request): Response {
        if (!Auth::check()) return redirect('/login');
        return parent::handle($request);
    }
}

class CorsMiddleware extends Middleware {
    public function handle(Request $request): Response {
        $response = parent->handle($request);
        $response->headers->set('Access-Control-Allow-Origin', '*');
        return $response;
    }
}

// 構建鏈(內核啟動時)
$app = new Application();
$app = new CorsMiddleware($app);
$app = new AuthMiddleware($app);
$app = new RateLimitMiddleware($app);
$app = new LoggingMiddleware($app);

// 處理請求
$response = $app->handle($request);

五、裝飾器 vs 繼承 vs 策略模式

維度裝飾器繼承策略模式
關係組合 (Has-A)繼承組合
靈活性運行時動態疊加編譯時固定運行時切換整體算法
擴展維度橫向添加職責縱向特化算法族替換
類爆炸無 (N+M)有 (N×M)無
透明性對客戶端透明透明客戶端知曉策略

六、最佳實踐原則

  1. 介面統一:裝飾器與被裝飾對象實現相同介面,保證透明替換
  2. 單一職責:每個裝飾器只負責一個具體功能(日誌、緩存、授權、壓縮、計費...)
  3. 避免過度裝飾:超過 5-7 層裝飾會影響可讀性與調試,考慮合併或用中介者
  4. 構造順序語義化:new Log(new Cache(new Auth($app))) 表示「先 Auth,再 Cache,再 Log」
  5. 支援移除/替換:提供 unwrap() 或工廠重建鏈,便於測試與動態配置

總結:裝飾器模式以組合替代繼承,為對象動態疊加職責。核心結構是「抽象組件介面 + 抽象裝飾器持有組件引用 + 具體裝飾器覆蓋/擴展行為」。它是構建中間件管道、流處理鏈、插件系統、UI 組件增強的標準模式。掌握「介面統一、單一職責、動態組合、順序語義」四要素,即可優雅解決繼承爆炸與靜態綁定難題。

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