兩個物件參與同一請求處理,接收請求的物件將工作委派給另一個物件完成。許多模式 (State, Strategy, Visitor) 本質上都是特定場景下的委派模式。
class Fruit {
public function callFruit() { print "Generate an Apple"; }
}
class FruitDelegator {
private $targets = [];
public function __construct() { $this->targets[] = new Fruit(); }
public function __call($name, $args) {
foreach ($this->targets as $obj) {
$r = new ReflectionClass($obj);
if ($method = $r->getMethod($name)) {
if ($method->isPublic() && !$method->isAbstract()) {
return $method->invoke($obj, $args);
}
}
}
}
}
$obj = new FruitDelegator();
$obj->callFruit(); // 輸出: Generate an Apple
class Color {
public function callColor() { print "Generate Red"; }
}
class ColorDelegator {
private $targets = [];
public function addObject($obj) { $this->targets[] = $obj; }
public function __call($name, $args) {
foreach ($this->targets as $obj) {
$r = new ReflectionClass($obj);
if ($method = $r->getMethod($name)) {
if ($method->isPublic() && !$method->isAbstract()) {
return $method->invoke($obj, $args);
}
}
}
}
}
$obj = new ColorDelegator();
$obj->addObject(new Color());
$obj->callColor(); // Generate Red
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'; }
}
$cd = new CD();
$cd->addSong("1"); $cd->addSong("2"); $cd->addSong("3");
$type = 'mp3';
if ($type == 'mp3') { $cd->playMp3(); } else { $cd->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\\' . ucfirst(strtolower($type)); // Mp3/Mp4
$strategy = new $className();
return $strategy->playList($this->cdInfo, $song);
}
}
$cd = new CDDelegate();
$cd->addSong("1"); $cd->addSong("2"); $cd->addSong("3");
echo $cd->play('mp3', '1'); // 1.mp3 - 僅傳遞參數,自動選擇策略
class PlayList {
private $_songs = [];
private $_object = null;
public function __construct($type) {
$class = $type . "PlayListDelegation";
$this->_object = new $class();
}
public function addSong($location, $title) {
$this->_songs[] = ['location'=>$location, 'title'=>$title];
}
public function getPlayList() {
return $this->_object->getPlayList($this->_songs);
}
}
class Mp3PlayListDelegation {
public function getPlayList($songs) {
return array_filter($songs, function($item) {
return pathinfo($item['location'], PATHINFO_EXTENSION) === 'mp3';
});
}
}
class RmvbPlayListDelegation {
public function getPlayList($songs) {
return array_filter($songs, function($item) {
return pathinfo($item['location'], PATHINFO_EXTENSION) === 'rmvb';
});
}
}
$mp3List = new PlayList("mp3");
$rmvbList = new PlayList("rmvb");
| 維度 | 委派模式 | 策略模式 |
|---|---|---|
| 關係 | 廣義概念 | 委派模式的具體化形式 |
| 介面 | 不強制要求 | 統一介面 (Strategy Interface) |
| 切換時機 | 靜態/動態皆可 | 運行時動態切換 |
| 核心目的 | 職責分離、代理轉發 | 算法族群封裝、可互換 |