abstract:委托模式是軟件設(shè)計(jì)模式中的一項(xiàng)基本技巧。在委托模式中,有兩個(gè)對象參與處理同一個(gè)請求,接受請求的對象將請求委托給另一個(gè)對象來處理。委托模式是一項(xiàng)基本技巧,許多其他的模式,如狀態(tài)模式、策略模式、訪問者模式本質(zhì)上是在更特殊的場合采用了委托模式。動(dòng)態(tài)委托的介紹:動(dòng)態(tài)委托概念來自于Jakarta 字節(jié)碼工程庫 (Byte-Code Engineering Library, BCEL)。它能夠分析存在的類,并
委托模式是軟件設(shè)計(jì)模式中的一項(xiàng)基本技巧。在委托模式中,有兩個(gè)對象參與處理同一個(gè)請求,接受請求的對象將請求委托給另一個(gè)對象來處理。委托模式是一項(xiàng)基本技巧,許多其他的模式,如狀態(tài)模式、策略模式、訪問者模式本質(zhì)上是在更特殊的場合采用了委托模式。
動(dòng)態(tài)委托的介紹:動(dòng)態(tài)委托概念來自于Jakarta 字節(jié)碼工程庫 (Byte-Code Engineering Library, BCEL)。它能夠分析存在的類,并且對于接口,抽象類,甚至運(yùn)行時(shí)的具體類來說,它能夠生成以字節(jié)編碼委托類。
被委托的接口/類應(yīng)該滿足如下條件:動(dòng)態(tài)委托最多只能委托一個(gè)類,但是能夠代理多個(gè)接口。這個(gè)限制來自于Java的單繼承模式。一個(gè)Java類最多只有一個(gè)父類。既然生成的委托類把被委托類作為它的父類,那么指定多個(gè)被委托類是不合理的。如果沒有指定被委托類,那么缺省的父類就是Object。
下面是PHP 反射機(jī)制實(shí)現(xiàn)動(dòng)態(tài)代理的代碼:
<?php class Fruit { function callFruit() { print "Generate an Apple"; } } class FruitDelegator { private $targets; function __construct() { $this->target[] = new Fruit(); } function __call($name, $args) { foreach ($this->target 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(); // 運(yùn)行結(jié)果 // Generate an Apple ?>
可見,通過代理類FruitDelegator來代替Fruit類來實(shí)現(xiàn)他的方法。
同樣的,如下的代碼也是能夠運(yùn)行的:
<?php class Color { function callColor() { print "Generate Red"; } } class ColorDelegator { private $targets; function addObject($obj) { $this->target[] = $obj; } function __call($name, $args) { foreach ($this->target 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(); ?>
設(shè)計(jì)了一個(gè)cd類,類中有mp3播放模式,和mp4播放模式
改進(jìn)前,使用cd類的播放模式,需要在實(shí)例化的類中去判斷選擇什么方式的播放模式
改進(jìn)后,播放模式當(dāng)做一個(gè)參數(shù)傳入playList函數(shù)中,就自動(dòng)能找到對應(yīng)需要播放的方法。
一、未改進(jìn)前
<?php //使用委托模式之前,調(diào)用cd類,選擇cd播放模式是復(fù)雜的選擇過程 class cd { protected $cdInfo = array(); 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(); }
二、通過委托模式,改進(jìn)后的cd類
<?php namespace Tools; /* 委托模式 去除核心對象中的判決和復(fù)雜功能性 */ //委托接口 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 = array(); public function addSong($song){ $this->cdInfo[$song] = $song; } public function play($type,$song){ $name = '\Tools\\'.$type; $obj = new $name; return $obj->playList($this->cdInfo,$song); } } $newCd = new cdDelegate(); $newCd->addSong("1"); $newCd->addSong("2"); $newCd->addSong("3"); echo $newCd->play('mp3','1');//只要傳遞參數(shù)就能知道需要選擇何種播放模式
再為大家分享一個(gè)實(shí)例:
<?php /** * 委托模式 示例 * * @create_date: 2010-01-04 */ class PlayList { var $_songs = array(); var $_object = null; function PlayList($type) { $object = $type."PlayListDelegation"; $this->_object = new $object(); } function addSong($location,$title) { $this->_songs[] = array("location"=>$location,"title"=>$title); } function getPlayList() { return $this->_object->getPlayList($this->_songs); } } class mp3PlayListDelegation { function getPlayList($songs) { $aResult = array(); foreach($songs as $key=>$item) { $path = pathinfo($item['location']); if(strtolower($item['extension']) == "mp3") { $aResult[] = $item; } } return $aResult; } } class rmvbPlayListDelegation { function getPlayList($songs) { $aResult = array(); foreach($songs as $key=>$item) { $path = pathinfo($item['location']); if(strtolower($item['extension']) == "rmvb") { $aResult[] = $item; } } return $aResult; } } $oMP3PlayList = new PlayList("mp3"); $oMP3PlayList->getPlayList(); $oRMVBPlayList = new PlayList("rmvb"); $oRMVBPlayList->getPlayList(); ?>
更多關(guān)于php設(shè)計(jì)模式之委托模式請關(guān)注PHP中文網(wǎng)(www.miracleart.cn)其他文章!