委托模式.docx

上传人:b****6 文档编号:4301633 上传时间:2022-11-29 格式:DOCX 页数:13 大小:32.85KB
下载 相关 举报
委托模式.docx_第1页
第1页 / 共13页
委托模式.docx_第2页
第2页 / 共13页
委托模式.docx_第3页
第3页 / 共13页
委托模式.docx_第4页
第4页 / 共13页
委托模式.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

委托模式.docx

《委托模式.docx》由会员分享,可在线阅读,更多相关《委托模式.docx(13页珍藏版)》请在冰豆网上搜索。

委托模式.docx

委托模式

php

/**

 *委托模式示例

 *

 *@create_date:

2010-01-04

 */

classPlayList

{

    var$_songs=array();

    var$_object=null;

 

    functionPlayList($type)

    {

        $object=$type."PlayListDelegation";

        $this->_object=new$object();

    }

 

    functionaddSong($location,$title)

    {

        $this->_songs[]=array("location"=>$location,"title"=>$title);

    }

 

    functiongetPlayList()

    {

        return$this->_object->getPlayList($this->_songs);

    }

}

 

classmp3PlayListDelegation

{

    functiongetPlayList($songs)

    {

        $aResult=array();

        foreach($songsas$key=>$item)

        {

            $path=pathinfo($item['location']);

            if(strtolower($item['extension'])=="mp3")

            {

                $aResult[]=$item;

            }

        }

        return$aResult;

    }

}

 

classrmvbPlayListDelegation

{

    functiongetPlayList($songs)

    {

        $aResult=array();

        foreach($songsas$key=>$item)

        {

            $path=pathinfo($item['location']);

            if(strtolower($item['extension'])=="rmvb")

            {

                $aResult[]=$item;

            }

        }

        return$aResult;

    }

}

 

$oMP3PlayList=newPlayList("mp3");

$oMP3PlayList->getPlayList();

$oRMVBPlayList=newPlayList("rmvb");

$oRMVBPlayList->getPlayList();

?

>

观察者模式里必须有两个角色:

消息发布者(subject)和消息接受者(observer)

委托模式也有两个角色:

委托者与被委托者

从行为和目的的角度来说,委托模式只是简单的将一件属于委托者做的事情,交给另外一个被委托者来处理,举个例子,如果你要写星际里面枪兵的攻击方法,可以设计为marine->attack(target)方法将真正的执行交给了marine->gun的gun->attack(target)方法:

//代码不是什么标准代码,保证你能看懂就行

classMarine

{

publicvoidsetGun(Gungun)

{

this->gun=gun;

}

publicvoidattack(Targettarget)

{

this->gun->attack(Targettarget);

}

}

//Machinegun实现了这个接口

interfaceGun

{

publicvoidattack(Targettarget);

}

委托一般的作用是将委托者与一些实际实现代码分离出来达成解耦的目的,试想如果需求变成枪兵可以在机枪和来复枪中切换,那么只用调用一下marine->setGun(ShotgunorMachinegun)就行了,被委托的方法attack一点都不用改变。

嗯,其实这个例子已经是有策略模式的感觉了,所以策略模式或者说状态模式等在本质上也就是委托模式的一种具体应用

委托模式是软件设计模式中的一项基本技巧。

在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。

委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。

委托模式使得我们可以用聚合来替代继承

简单的Java例子

在这个例子里,类模拟打印机Printer拥有针式打印机RealPrinter的实例,Printer拥有的方法print()将处理转交给RealPrinter的print()方法。

classRealPrinter{//the"delegate"

voidprint(){

System.out.print("something");

}

}

classPrinter{//the"delegator"

RealPrinterp=newRealPrinter();//createthedelegate

voidprint(){

p.print();//delegation

}

}

publicclassMain{

//totheoutsideworlditlookslikePrinteractuallyprints.

publicstaticvoidmain(String[]args){

Printerprinter=newPrinter();

printer.print();

}

}

复杂的Java例子

通过使用接口,委托可以做到类型安全并且更加灵活。

在这个例子里,类C可以委托类A或类B,类C拥有方法使自己可以在类A或类B间选择。

因为类A或类B必须实现接口I规定的方法,所以在这里委托是类型安全的。

这个例子显示出委托的缺点是需要更多的代码。

interfaceI{

voidf();

voidg();

}

classAimplementsI{

publicvoidf(){System.out.println("A:

doingf()");}

publicvoidg(){System.out.println("A:

doingg()");}

}

classBimplementsI{

publicvoidf(){System.out.println("B:

doingf()");}

publicvoidg(){System.out.println("B:

doingg()");}

}

classCimplementsI{

//delegation

Ii=newA();

publicvoidf(){i.f();}

publicvoidg(){i.g();}

//normalattributes

publicvoidtoA(){i=newA();}

publicvoidtoB(){i=newB();}

}

publicclassMain{

publicstaticvoidmain(String[]args){

Cc=newC();

c.f();//output:

A:

doingf()

c.g();//output:

A:

doingg()

c.toB();

c.f();//output:

B:

doingf()

c.g();//output:

B:

doingg()

}

}

PHP设计模式系列-委托模式

委托模式

通过分配或委托其他对象,委托设计模式能够去除核心对象中的判决和复杂的功能性。

应用场景

设计了一个cd类,类中有mp3播放模式,和mp4播放模式

改进前,使用cd类的播放模式,需要在实例化的类中去判断选择什么方式的播放模式

改进后,播放模式当做一个参数传入playList函数中,就自动能找到对应需要播放的方法。

代码:

cd类,未改进之前,选择播放模式是一种痛苦的事情

php

//委托模式-去除核心对象中的判决和复杂的功能性

//使用委托模式之前,调用cd类,选择cd播放模式是复杂的选择过程

classcd{

protected$cdInfo=array();

publicfunctionaddSong($song){

$this->cdInfo[$song]=$song;

}

publicfunctionplayMp3($song){

return$this->cdInfo[$song].'.mp3';

}

publicfunctionplayMp4($song){

return$this->cdInfo[$song].'.mp4';

}

}

$oldCd=newcd;

$oldCd->addSong("1");

$oldCd->addSong("2");

$oldCd->addSong("3");

$type='mp3';

if($type=='mp3'){

$oldCd->playMp3();

}else{

$oldCd->playMp4();

}

?

>

php

//委托模式-去除核心对象中的判决和复杂的功能性

//改进cd类

classcdDelegate{

protected$cdInfo=array();

publicfunctionaddSong($song){

$this->cdInfo[$song]=$song;

}

publicfunctionplay($type,$song){

$obj=new$type;

return$obj->playList($this->cdInfo,$song);

}

}

classmp3{

publicfunctionplayList($list){

return$list[$song];

}

}

classmp4{

publicfunctionplayList($list){

return$list[$song];

}

}

$newCd=newcd;

$newCd->addSong("1");

$newCd->addSong("2");

$newCd->addSong("3");

$type='mp3';

$oldCd->play('mp3','1');//只要传递参数就能知道需要选择何种播放模式

委托设计模式致力于从核心对象中去除复杂性。

此时我们并不设计极大依赖于通过评估条件语句而执行特定功能性的对象,基于委托模式的对象能够将判决委托给不同的对象。

委托既可以像使用中间对象处理判决树一样简单。

也可以像使用动态实例化对象提供期望的功能一样复杂。

不要将委托设计模式视为条件语句的直接竞争者,这是非常重要的。

相反,委托设计模式通过不需要条件语句就可以调用正确功能性的方式来帮助构成体系结构。

条件语句最好驻留在实际方法中,并且在方法中完成对业务规则的处理。

委托设计模式的一个使用示例是为特定数据部分提供多种格式。

假设在开放源代码库中存在一个归档。

当访问者打算下载部分源代码时,他们可以选择两种不同格式的文件。

指定文件被压缩后将被发送至浏览器。

在这个示例中,我打算釆用zip和tgz压缩格式的文件。

通常,我们需要创建一个文件收集和下载对象。

这个对象具有收集被请求文件以及再将对这些文件的引用存储在内部的方法。

随后,专门用于指定压缩类型的方法会被调用。

如果压缩类型为zip,那么就会调用generateZip()方法。

我们应当使用基于委托设计模式的对象来取代上述约定的函数。

generateZip()方法的功能性应当被转移至针对基对象的文件列表执行该功能的Delegate类.这不仅可以减少基对象的复杂性,而且也可以为代码提供更好的可维护性,如果要采用新的压缩类型(如.dmg),那么只需要创建新的Delegate对象。

稳定的基对象并不需要被编辑。

当一个对象包含复杂但独立的,必须基于判决执行的功能性的若干部分时。

最佳的做法是使用基于委托设计模式的对象。

如图7-1所示,该UML图详细说明了一个使用委托设计模式的类设计。

.3代码示例

示例中的Web站点具有创建MP3文件播放列表的功能。

MP3文件可以来自访问者的硬盘驱动器,也可以来自Internet访问者可以选择以M3U或PLS格式下载播放列表。

为了节省篇幅,具休的代码示例只会显示播放列表的创建部分。

如下所示,第一个步骤是创建Playlist类:

classPlaylist

{

private$__songs;

publicfunction__construct()

{

$this->__songs=array();

}

publicfunctionaddSong($location,$title)

{

$song=array(‘location’=>$location,‘title'=>$title);

$this->__songs[]=$song,

}

publicfunctiongetM3U()

$m3u="EXTM3U\n\n”;

foreach($this->__songsas$song)f

$m3u.="#EXTINF:

-l,{$song[‘title’]}\n";

$m3u.=”{$song[‘location‘]}\n";

}

return$m3u;

}

publicfunctiongetPLS(){

$pls=”[playlist]\nNumbecOfEntries=".count{$this->__songs).”\n\n";

foreach($this->_songsas$songCount=>$song){

$counter=$songCount+1;

$pls.=”File{$counter}={$song[‘loaction’]}\n”;

$pls.=”File{$counter}={$song[‘title]}\n”;

$pls.=”length{$counter}=-1\n\n”;

}

return$pls;

}

}

Playlist对象存储一个歌曲数组,这个数组是由构造数组初始化的,

addSong()公共方法接受两个参数:

MP3文件的位置和该文件的标题.这两个参数组成一个关联数组,随后被添加至内部的歌曲数组,

具体的需求规定播放列表必须可以任意使用M3U和PLS格式。

为此,Playlist类具有getM3U()和getPLS()两个方法。

这两个方法都负责创建适当的播放列表文件头并遍历内部的歌曲数组以完成播放列表。

之后,每个方法都会返回釆用字符字符串格式的播放列表。

如下所示,执行上述功能性的当前代码包含了常见的if/else子句:

$playlist=newPlaylist();

$playlist->addSong(‘/home/aaron/music/brr.mp3','brr’);

$playlist->addSong(‘/home/aaron/music/goodbye.mp3',goodbye);

if($externalRetirievedType='pls'){

$playlistContent=$playlist->getPLS();

}else{

$playlistContent=$playlist->getM3U();

}

上面的代码创建了Playlist对象的一个新实例,添加了两个歌曲位置和标题,接着创建了一个if/else子句。

如果格式类型为pls,那么就执行getPLS()方法,其输出被置入变量$playlistContent否则,$externalRetirievedType可能包含m3u,这将进入if/else子句的else部分。

这个Web站点的销售团队发现至少可以使用5种以上播放列表格式,因此,他们在开发之前就开始推销相应的软件功能,那时,编程人识仍然不知道哪种新播放列表格式会被出售.

在这一时期,编程人员可以使用委托设计模式来改代码。

这种做法的目的是消除潜在的、难以控制的出else语句此外,随着添加更多的代码。

最初的Playlist类会变得极为庞大。

创建newPlaylist类是因为意识到要使用委托设计模式的事实。

PHP动态创建基于某个变量的类实例的能力也十分有用。

classnewPlaylist{

private$__songs;

private$__typeObject;

publicfunction__construct($type)

{

$this->__songs=array();

$object=“{$type}Playlist”;

$this->__typeObject=new$object;

}

publicfunctionaddSong($location,$title)

{

$song=array(‘location’=>$location,'title’=>$title);

$this->songs[]=$song;

}

publicfunctiongetPlaylist()

{

$playlist=$this->__typeObject->getPlaylist($this->__songs);

return$playlist;

}

}

newPlaylist对象的构造函数现在接受$type参数。

除了初始化内部的歌曲数组之外,构造函数还可以根据$type动态地创建指定委托的新实例并将该实例内部存储在$__typeObject变量中。

addSongs()方法与最初Playlist对象所包含的方法相同。

getM3U()和getPLS()方法被替换为getPlaylist()方法。

这个方法执行内部存储的委托对象的getPlaylist()方法,它将歌曲数组传递指定对象,从而使该对象能够创建和返冋正确的播放列表。

如下所示,作为Playlist对象原有的上述两个方法被移动至这些对象自己的委托对象:

classm3uPlaylistDelegate{

publicfunctiongetPlaylist(?

songs)

{

$m3u="EXTM3U\n\n”;

foreach($songsas$song){

$m3u.="*#EXTrNF:

-l,{$song[‘title’]}\n";

$m3u.=”{$song[‘location‘]}\n";

}

return$m3u;

}

classplsPlaylistDelegate

{

publicfunctiongetPlaylist($songs)

{

$pls=”[playlist]\nNumbecOfEntries=".count{$songs).”\n\n";

foreach($songsas$songCount=>$song)(

$counter=$songCount+1;

$pls.=”File{$counter}={$song[‘loaction’]}\n”;

$pls.=”File{$counter}={$song[‘title]}\n”;

$pls.=”length{$counter}=-1\n\n”;

}

return$pls;

}

}

每个委托类本质上都只是重新包装基类Playlist中的原有方法。

每个委托对象都具有完全相同的指定公共方法getPlaylist(),该方法接受songs参数。

这种方式使基对象能够简单、动态地创建和访问任何委托者。

如下所示,执行这个基于委托的新系统的代码更为简单:

$externalRetrievedType=‘pls’;

$playlist=newnewPiaylist($externalRetrievedType);

$playlistContent=$playlist->getPlaylist();

当通告其他播放列表格式时。

开发人员不必修改上面的代码就能够创建基于委托设计模式的新类。

为了去除核心对象的复杂性并且能够动态添加新的功能,就应当使用委托设计模式。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 理化生

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1