模式意圖
在不修改原類、不使用繼承的前提下,**動態**為物件添加新職責。比生成子類更靈活,避免類爆炸與層級過深。
四大角色
| 角色 | 說明 |
| Component(抽象構件) | 定義核心介面 |
| ConcreteComponent(具體構件) | 被裝飾的核心實現 |
| Decorator(抽象裝飾者) | 持有 Component 引用,實現 Component 介面 |
| ConcreteDecorator(具體裝飾者) | 添加具體職責,可鏈式組合 |
核心代碼實現
<?php
// Component
interface Component {
public function operation(): void;
}
// ConcreteComponent
class ConcreteComponent implements Component {
public function operation(): void {
echo "Core Operation\n";
}
}
// Decorator(抽象裝飾者)
abstract class Decorator implements Component {
protected Component $component;
public function __construct(Component $component) {
$this->component = $component;
}
public function operation(): void {
$this->component->operation(); // 委託核心
}
}
// ConcreteDecoratorA
class DecoratorA extends Decorator {
public function operation(): void {
parent::operation();
$this->addedBehaviorA();
}
private function addedBehaviorA(): void {
echo " + Behavior A\n";
}
}
// ConcreteDecoratorB
class DecoratorB extends Decorator {
public function operation(): void {
parent::operation();
$this->addedBehaviorB();
}
private function addedBehaviorB(): void {
echo " + Behavior B\n";
}
}
// Client
$core = new ConcreteComponent();
$withA = new DecoratorA($core);
$withAB = new DecoratorB($withA); // 疊加裝飾
$withAB->operation();
/* 輸出:
Core Operation
+ Behavior A
+ Behavior B
*/
經典應用場景
| 領域 | Component | Decorators |
| I/O 流 | Stream | Buffered, Gzip, Encryption, Logging |
| HTTP 中介軟體 | RequestHandler | Auth, RateLimit, Cors, Cache, Metrics |
| 日誌記錄 | Logger | Timestamp, LevelFilter, Formatter, RemoteShipper |
| 緩存 | Cache | Serialization, Compression, Encryption, Fallback |
| 模板渲染 | Renderer | Layout, Escape, Minify, Cache |
PHP 內建裝飾者案例
SplFileObject 裝飾文件指針,添加 CSV、定位、迭代能力
FilterIterator 族裔裝飾迭代器,添加過濾/映射/限制行為
- PSR-15 中介軟體管道:
RequestHandlerInterface 為 Component,各中介軟體為 Decorator
裝飾者 vs 繼承 vs 組合
| 維度 | 繼承 | 裝飾者 | 純組合 |
| 靜態/動態 | 編譯期靜態 | 運行期動態 | 運行期動態 |
| 組合爆炸 | 易發生 | 避免 | 手動管理 |
| 單一職責 | 違反(子類承擔多職責) | 符合(每飾一責) | 視設計而定 |
| 類型兼容 | 是(is-a) | 是(is-a) | 否(has-a) |
避坑指南
- 裝飾者**必須實現與被裝飾者相同介面**,保證透明替換
- 避免在裝飾鏈中依賴具體類型(
instanceof ConcreteComponent),破壞多態性
- 過深裝飾鏈影響除錯可讀性,核心鏈路建議 ≤ 5 層
- 區別裝飾者(增強行為)與代理(控制訪問):代理不添加業務職責
裝飾者模式是「組合優於繼承」原則的教科書級落地,掌握它能讓你的系統擁有如樂高般的擴展靈活性。