裝飾器模式允許在不修改原類代碼、不使用繼承的情況下,動態為物件添加新行為。本文通過「畫板繪圖」實例,對比傳統繼承與裝飾器模式,展示如何實現繪圖功能的靈活組合擴展。
基礎 Canvas 類支援初始化畫布、繪製矩形、輸出字符畫:
class Canvas {
public $data;
public function init($width = 20, $height = 10) { /* 初始化 * 陣列 */ }
public function rect($a1, $a2, $b1, $b2) { /* 繪製矩形區域 */ }
public function draw() { /* 輸出字符畫 */ }
}
調用:$canvas->init(40,20)->rect(4,15,9,30)->draw(); 輸出矩形字符畫。
若需增加「顏色」、「加粗」、「標題」等樣式,傳統做法:
draw() 硬編碼 HTML 標籤 → 違反開閉原則ColorCanvas、BoldCanvas → 組合爆炸,靈活性差interface DrawDecorator {
public function beforeDraw();
public function afterDraw();
}
class ColorDrawDecorator implements DrawDecorator {
protected $color;
public function __construct($color = 'red') { $this->color = $color; }
public function beforeDraw() { echo "<div style='color:{$this->color}'>"; }
public function afterDraw() { echo "</div>"; }
}
class Canvas {
public $data;
protected $decorators = [];
public function addDecorator(DrawDecorator $decorator) {
$this->decorators[] = $decorator;
}
protected function beforeDraw() {
foreach ($this->decorators as $d) $d->beforeDraw();
}
protected function afterDraw() {
foreach (array_reverse($this->decorators) as $d) $d->afterDraw();
}
public function draw() {
$this->beforeDraw();
// 原有繪圖邏輯
$this->afterDraw();
}
// init、rect 等方法保持不變...
}
$canvas = new Canvas();
$canvas->addDecorator(new ColorDrawDecorator('green')); // 注入綠色裝飾器
$canvas->init(40, 20);
$canvas->rect(4, 15, 9, 30);
$canvas->draw(); // 輸出綠色矩形
新增需求只需建立新裝飾器類,無需修改 Canvas:
BoldDrawDecorator → 加粗ItalicDrawDecorator → 傾斜TitleDrawDecorator → 添加標題多裝飾器疊加:$canvas->addDecorator(new ColorDrawDecorator('red'))->addDecorator(new BoldDrawDecorator());
裝飾器本質類似「鉤子機制」,Drupal 的 Hook 系統、WordPress 的 Filter/Action 機制皆為此模式變體。亦可用 call_user_func_array 實現輕量級裝飾器調度。
掌握裝飾器模式,能讓你在面對頻繁變化的橫切關注點(日誌、緩存、權限、樣式)時,從容應對,寫出可維護、可擴展的優雅代碼。