委派模式擴展類別功能的方法:編寫附加類別提供新功能,並使用原類別實例提供原有功能。
TeamLead 將 writeCode 任務委派給 JuniorDeveloper 的 writeBadCode 實現,調用者 Usage 無感知。
class CD {
protected $cdInfo = [];
public function addSong($song) { $this->cdInfo[$song] = $song; }
public function playMp3($song) { return $this->cdInfo[$song] . '.mp3'; }
public function playMp4($song) { return $this->cdInfo[$song] . '.mp4'; }
}
$oldCd = new CD();
$oldCd->addSong("1"); $oldCd->addSong("2"); $oldCd->addSong("3");
$type = 'mp3';
if ($type == 'mp3') { $oldCd->playMp3(); } else { $oldCd->playMp4(); }
namespace Tools;
// 委派介面
interface Delegate {
public function playList($list, $song);
}
// MP3 策略
class Mp3 implements Delegate {
public function playList($list, $song) { return $list[$song] . '.mp3'; }
}
// MP4 策略
class Mp4 implements Delegate {
public function playList($list, $song) { return $list[$song] . '.mp4'; }
}
// 核心委派類別
class CDDelegate {
protected $cdInfo = [];
public function addSong($song) { $this->cdInfo[$song] = $song; }
public function play($type, $song) {
$className = '\\Tools\\' . $type; // 直接使用型別名稱
$strategy = new $className();
return $strategy->playList($this->cdInfo, $song);
}
}
$newCd = new CDDelegate();
$newCd->addSong("1"); $newCd->addSong("2"); $newCd->addSong("3");
echo $newCd->play('mp3', '1'); // 僅傳遞參數,自動路由到對應策略
| 方面 | 重構前 | 重構後 |
|---|---|---|
| 判斷邏輯位置 | 客戶端代碼中 | 委派類別內部 (工廠式建立策略) |
| 新增播放格式 | 修改 CD 類別 + 客戶端 | 新增策略類別實現 Delegate 介面 |
| 開放封閉原則 | 違反 (修改現有代碼) | 符合 (擴展新策略類別) |
| 單一職責 | CD 類別兼管資料與播放邏輯 | CDDelegate 管資料,策略類別管播放 |
| 客戶端複雜度 | 需知曉具體播放方法 | 僅需傳遞型別參數 |
Mp3, Mp4)