<接上一篇>


5、中介者模式(Mediator):

用中介对象封装一系列的对象交互,中介使各对象不需要显式地相互引用。类似于邮局,邮寄者和收件者不用自己跑很远路,通过邮局就可以。

好处:简化了对象之间的关系,减少子类的生成

弊端:中介对象可能变得非常复杂,系统难以维护

应用场景:不需要显示地建立交互

代码实现:


<?php/***优才网公开课示例代码**中介者模式Mediator**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*/functionoutput($string){echo$string."\n";}abstractclassMediator{//中介者角色abstractpublicfunctionsend($message,$colleague);}abstractclassColleague{//抽象对象private$_mediator=null;publicfunction__construct($mediator){$this->_mediator=$mediator;}publicfunctionsend($message){$this->_mediator->send($message,$this);}abstractpublicfunctionnotify($message);}classConcreteMediatorextendsMediator{//具体中介者角色private$_colleague1=null;private$_colleague2=null;publicfunctionsend($message,$colleague){if($colleague==$this->_colleague1){$this->_colleague1->notify($message);}else{$this->_colleague2->notify($message);}}publicfunctionset($colleague1,$colleague2){$this->_colleague1=$colleague1;$this->_colleague2=$colleague2;}}classColleague1extendsColleague{//具体对象角色publicfunctionnotify($message){output(sprintf('Colleague-1:%s',$message));}}classColleague2extendsColleague{//具体对象角色publicfunctionnotify($message){output(sprintf('Colleague-2:%s',$message));}}classClient{publicstaticfunctiontest(){//client$objMediator=newConcreteMediator();$objC1=newColleague1($objMediator);$objC2=newColleague2($objMediator);$objMediator->set($objC1,$objC2);$objC1->send("toc2fromc1");$objC2->send("toc1fromc2");}}Client::test();


6、状态模式(State) :

对象在不同状态下表现出不同的行为。就像女朋友一样,高兴了牵你的手,不高兴了遛狗。在两种状态下变现出不同的行为。

好处:避免if语句实用,方便增加新状态,封装了状态转换规则。

弊端:增加系统类和对象的数量。

应用场景:用于对象的不同功能的转换。

代码实现:


<?php/***优才网公开课示例代码**状态模式State**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*/functionoutput($string){echo$string."\n";}abstractclassILift{//电梯的四个状态constOPENING_STATE=1;//门敞状态constCLOSING_STATE=2;//门闭状态constRUNNING_STATE=3;//运行状态constSTOPPING_STATE=4;//停止状态;//设置电梯的状态publicabstractfunctionsetState($state);//首先电梯门开启动作publicabstractfunctionopen();//电梯门有开启,那当然也就有关闭了publicabstractfunctionclose();//电梯要能上能下,跑起来publicabstractfunctionrun();//电梯还要能停下来publicabstractfunctionstop();}/***电梯的实现类*/classLiftextendsILift{private$state;publicfunctionsetState($state){$this->state=$state;}//电梯门关闭publicfunctionclose(){//电梯在什么状态下才能关闭switch($this->state){caseILift::OPENING_STATE://如果是则可以关门,同时修改电梯状态$this->setState(ILift::CLOSING_STATE);break;caseILift::CLOSING_STATE://如果电梯就是关门状态,则什么都不做//donothing;return;break;caseILift::RUNNING_STATE://如果是正在运行,门本来就是关闭的,也说明都不做//donothing;return;break;caseILift::STOPPING_STATE://如果是停止状态,本也是关闭的,什么也不做//donothing;return;break;}output('Liftcolse');}//电梯门开启publicfunctionopen(){//电梯在什么状态才能开启switch($this->state){caseILift::OPENING_STATE://如果已经在门敞状态,则什么都不做//donothing;return;break;caseILift::CLOSING_STATE://如是电梯时关闭状态,则可以开启$this->setState(ILift::OPENING_STATE);break;caseILift::RUNNING_STATE://正在运行状态,则不能开门,什么都不做//donothing;return;break;caseILift::STOPPING_STATE://停止状态,淡然要开门了$this->setState(ILift::OPENING_STATE);break;}output('Liftopen');}///电梯开始跑起来publicfunctionrun(){switch($this->state){caseILift::OPENING_STATE://如果已经在门敞状态,则不你能运行,什么都不做//donothing;return;break;caseILift::CLOSING_STATE://如是电梯时关闭状态,则可以运行$this->setState(ILift::RUNNING_STATE);break;caseILift::RUNNING_STATE://正在运行状态,则什么都不做//donothing;return;break;caseILift::STOPPING_STATE://停止状态,可以运行$this->setState(ILift::RUNNING_STATE);}output('Liftrun');}//电梯停止publicfunctionstop(){switch($this->state){caseILift::OPENING_STATE://如果已经在门敞状态,那肯定要先停下来的,什么都不做//donothing;return;break;caseILift::CLOSING_STATE://如是电梯时关闭状态,则当然可以停止了$this->setState(ILift::CLOSING_STATE);break;caseILift::RUNNING_STATE://正在运行状态,有运行当然那也就有停止了$this->setState(ILift::CLOSING_STATE);break;caseILift::STOPPING_STATE://停止状态,什么都不做//donothing;return;break;}output('Liftstop');}}classClient{publicstaticfunctiontest(){$lift=newLift();//电梯的初始条件应该是停止状态$lift->setState(ILift::STOPPING_STATE);//首先是电梯门开启,人进去$lift->open();//然后电梯门关闭$lift->close();//再然后,电梯跑起来,向上或者向下$lift->run();//最后到达目的地,电梯挺下来$lift->stop();}}Client::test();


<?php/***优才网公开课示例代码**状态模式State**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*/functionoutput($string){echo$string."\n";}/****定义一个电梯的接口*/abstractclassLiftState{//定义一个环境角色,也就是封装状态的变换引起的功能变化protected$_context;publicfunctionsetContext(Context$context){$this->_context=$context;}//首先电梯门开启动作publicabstractfunctionopen();//电梯门有开启,那当然也就有关闭了publicabstractfunctionclose();//电梯要能上能下,跑起来publicabstractfunctionrun();//电梯还要能停下来,停不下来那就扯淡了publicabstractfunctionstop();}/***环境类:定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。*/classContext{//定义出所有的电梯状态static$openningState=null;static$closeingState=null;static$runningState=null;static$stoppingState=null;publicfunction__construct(){self::$openningState=newOpenningState();self::$closeingState=newClosingState();self::$runningState=newRunningState();self::$stoppingState=newStoppingState();}//定一个当前电梯状态private$_liftState;publicfunctiongetLiftState(){return$this->_liftState;}publicfunctionsetLiftState($liftState){$this->_liftState=$liftState;//把当前的环境通知到各个实现类中$this->_liftState->setContext($this);}publicfunctionopen(){$this->_liftState->open();}publicfunctionclose(){$this->_liftState->close();}publicfunctionrun(){$this->_liftState->run();}publicfunctionstop(){$this->_liftState->stop();}}/***在电梯门开启的状态下能做什么事情*/classOpenningStateextendsLiftState{/***开启当然可以关闭了,我就想测试一下电梯门开关功能**/publicfunctionclose(){//状态修改$this->_context->setLiftState(Context::$closeingState);//动作委托为CloseState来执行$this->_context->getLiftState()->close();}//打开电梯门publicfunctionopen(){output('liftopen...');}//门开着电梯就想跑,这电梯,吓死你!publicfunctionrun(){//donothing;}//开门还不停止?publicfunctionstop(){//donothing;}}/***电梯门关闭以后,电梯可以做哪些事情*/classClosingStateextendsLiftState{//电梯门关闭,这是关闭状态要实现的动作publicfunctionclose(){output('liftclose...');}//电梯门关了再打开,逗你玩呢,那这个允许呀publicfunctionopen(){$this->_context->setLiftState(Context::$openningState);//置为门敞状态$this->_context->getLiftState()->open();}//电梯门关了就跑,这是再正常不过了publicfunctionrun(){$this->_context->setLiftState(Context::$runningState);//设置为运行状态;$this->_context->getLiftState()->run();}//电梯门关着,我就不按楼层publicfunctionstop(){$this->_context->setLiftState(Context::$stoppingState);//设置为停止状态;$this->_context->getLiftState()->stop();}}/***电梯在运行状态下能做哪些动作*/classRunningStateextendsLiftState{//电梯门关闭?这是肯定了publicfunctionclose(){//donothing}//运行的时候开电梯门?你疯了!电梯不会给你开的publicfunctionopen(){//donothing}//这是在运行状态下要实现的方法publicfunctionrun(){output('liftrun...');}//这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了publicfunctionstop(){$this->_context->setLiftState(Context::$stoppingState);//环境设置为停止状态;$this->_context->getLiftState()->stop();}}/***在停止状态下能做什么事情*/classStoppingStateextendsLiftState{//停止状态关门?电梯门本来就是关着的!publicfunctionclose(){//donothing;}//停止状态,开门,那是要的!publicfunctionopen(){$this->_context->setLiftState(Context::$openningState);$this->_context->getLiftState()->open();}//停止状态再跑起来,正常的很publicfunctionrun(){$this->_context->setLiftState(Context::$runningState);$this->_context->getLiftState()->run();}//停止状态是怎么发生的呢?当然是停止方法执行了publicfunctionstop(){output('liftstop...');}}/***模拟电梯的动作*/classClient{publicstaticfunctiontest(){$context=newContext();$context->setLiftState(newClosingState());$context->open();$context->close();$context->run();$context->stop();}}Client::test();


7、职责链模式 (Chainof Responsibility):

多个对象有机会处理请求,为请求发送者和接收者解耦。就像银行里的取款机,不管那一台都可以取到钱。

好处:简单化对象隐藏链结构,便于添加新职责节点

弊端:请求可能没有接受者,或者被多个接收者调用,性能降低

应用场景:处理多种请求

代码实现:


<?php/***优才网公开课示例代码**职责链模式ChainofResponsibility**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*/functionoutput($string){echo$string."\n";}/***加入在公司里,如果你的请假时间小于0.5天,那么只需要向leader打声招呼就OK了。  如果0.5<=请假天数<=3天,需要先leader打声招呼,然后部门经理签字。  如果3<请假天数,需要先leader打声招呼,然后到部门经理签字,最后总经经理确认签字,如果请假天数超过10天,是任何人都不能批准的。*//***抽象处理者角色(Handler:Approver):定义一个处理请求的接口,和一个后继连接(可选)**/abstractclassHandler{protected$_handler=null;protected$_handlerName=null;publicfunctionsetSuccessor($handler){$this->_handler=$handler;}protectedfunction_success($request){output(sprintf("%s'srequestwaspassed",$request->getName()));returntrue;}abstractfunctionhandleRequest($request);}/***具体处理者角色(ConcreteHandler:President):处理它所负责的请求,可以访问后继者,如果可以处理请求则处理,否则将该请求转给他的后继者。**/classConcreteHandlerLeaderextendsHandler{function__construct($handlerName){$this->_handlerName=$handlerName;}publicfunctionhandleRequest($request){if($request->getDay()<0.5){output(sprintf('%swastold',$this->_handlerName));//已经跟leader招呼了return$this->_success($request);}if($this->_handlerinstanceofHandler){return$this->_handler->handleRequest($request);}}}/***Manager**/classConcreteHandlerManagerextendsHandler{function__construct($handlerName){$this->_handlerName=$handlerName;}publicfunctionhandleRequest($request){if(0.5<=$request->getDay()&&$request->getDay()<=3){output(sprintf('%ssigned',$this->_handlerName));//部门经理签字return$this->_success($request);}if($this->_handlerinstanceofHandler){return$this->_handler->handleRequest($request);}}}classConcreteHandlerGeneralManagerextendsHandler{function__construct($handlerName){$this->_handlerName=$handlerName;}publicfunctionhandleRequest($request){if(3<$request->getDay()&&$request->getDay()<10){output(sprintf('%ssigned',$this->_handlerName));//总经理签字return$this->_success($request);}if($this->_handlerinstanceofHandler){return$this->_handler->handleRequest($request);}else{output(sprintf('noonecanapproverequestmorethan10days'));}}}/***请假申请**/classRequest{private$_name;private$_day;private$_reason;function__construct($name='',$day=0,$reason=''){$this->_name=$name;$this->_day=$day;$this->_reason=$reason;}publicfunctionsetName($name){$this->_name=$name;}publicfunctiongetName(){return$this->_name;}publicfunctionsetDay($day){$this->_day=$day;}publicfunctiongetDay(){return$this->_day;}publicfunctionsetReason($reason){$this->_reason=$reason;}publicfunctiongetReason(){return$this->_reason;}}classClient{publicstaticfunctiontest(){$leader=newConcreteHandlerLeader('leader');$manager=newConcreteHandlerManager('manager');$generalManager=newConcreteHandlerGeneralManager('generalManager');//请求实例$request=newRequest('ucai',4,'休息');$leader->setSuccessor($manager);$manager->setSuccessor($generalManager);$result=$leader->handleRequest($request);}}Client::test();


8、策略模式(Strategy):

定义一系列算法,把每一个算法封装起来,并且使它们可相互替换。就像篮球队里的球员,场上的和场下休息的。教练可以让场上的下来,也可以让场下的上阵。

好处:定义可重用的一系列算法和行为,并且消除了if else语句

弊端:调用端必须知道所有策略类

应用场景:用于对象间的替换

代码实现:


<?php/***优才网公开课示例代码**策略模式Strategy**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*/functionoutput($string){echo$string."\n";}//策略基类接口interfaceIStrategy{publicfunctionOnTheWay();}classWalkStrategyimplementsIStrategy{publicfunctionOnTheWay(){output('在路上步行');}}classRideBickStrategyimplementsIStrategy{publicfunctionOnTheWay(){output('在路上骑自行车');}}classCarStrategyimplementsIStrategy{publicfunctionOnTheWay(){output('在路上开车');}}//选择策略类ContextclassContext{publicfunctionfind($strategy){$strategy->OnTheWay();}}classClient{publicstaticfunctiontest(){$travel=newContext();$travel->find(newWalkStrategy());$travel->find(newRideBickStrategy());$travel->find(newCarStrategy());}}Client::test();


已知模式

1、备忘录模式(Memento):

保存对象在一时刻的状态。亲,还记得“老师来了记得叫我一下”的同桌的他吗?

好处:给用户提供了一种可以恢复状态的机制

弊端:消耗资源

应用场景:用于需要保存的数据

代码实现:


<?php/***优才网公开课示例代码**备忘录模式Memento**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*/functionoutput($string){echo$string."\n";}classOriginator{//发起人(Originator)角色private$_state;publicfunction__construct(){$this->_state='';}publicfunctioncreateMemento(){//创建备忘录returnnewMemento($this->_state);}publicfunctionrestoreMemento(Memento$memento){//将发起人恢复到备忘录对象记录的状态上$this->_state=$memento->getState();}publicfunctionsetState($state){$this->_state=$state;}publicfunctiongetState(){return$this->_state;}publicfunctionshowState(){output($this->_state);}}classMemento{//备忘录(Memento)角色private$_state;publicfunction__construct($state){$this->setState($state);}publicfunctiongetState(){return$this->_state;}publicfunctionsetState($state){$this->_state=$state;}}classCaretaker{//负责人(Caretaker)角色private$_memento;publicfunctiongetMemento(){return$this->_memento;}publicfunctionsetMemento(Memento$memento){$this->_memento=$memento;}}classClient{publicstaticfunctiontest(){$org=newOriginator();$org->setState('open');$org->showState();/*创建备忘*/$memento=$org->createMemento();/*通过Caretaker保存此备忘*/$caretaker=newCaretaker();$caretaker->setMemento($memento);/*改变目标对象的状态*/$org->setState('close');$org->showState();/*还原操作*/$org->restoreMemento($caretaker->getMemento());$org->showState();}}Client::test();return;try{$db->beginTransaction();$succ=$db->exec($sql_1);if(!$succ){thrownewException('SQL1updatefailed');}$succ=$db->exec($sql_2);if(!$succ){thrownewException('SQL2updatefailed');}$succ=$db->exec($sql_3);if(!$succ){thrownewException('SQL3updatefailed');}$db->commit();}catch(Exception$exp){$db->rollBack();}

深度模式


1、解释器模式(Interpreter):

定义语言的文法,并建立一个解释器解释该语言中的句子。每个用过字典的童鞋都懂滴。

好处:可扩展性比较好,灵活性大

弊端:可能难以维护复杂的文法

应用场景:用于成对或者一对多的需求中


2、访问者模式(Visitor):

封装某些用于作用于某种数据结构中各元素的操作,可以在不改变数据结构的前提下定义作用于这些元素的新操作。如银行排号机。

好处:将相关的事物集中到一个访问者对象中。

弊端:增加新数据结构很困难

应用场景:排队,排号


三、总结

本篇介绍了行为型模式,行为模式涉及到算法和对象职责间的分配,行为类模式采用继承机制在类间分派行为,TemplateMethod和Interpreter是类行为模式。行为对象模式使用对象复合而不是继承,一些行为对象模式描述了一组相互对等的对象如何相互协作以完成其中任何一个对象都单独无法完成的任务,如Mediator在对象间引入一个mediator对象提供了松耦合所需的间接性;Chain of Responsibility提供了更松的耦合,它通过一条候选对象链隐式的向一个对象发松请求,可以运行时刻决定哪些候选者参与到链中;Observer定义并保持了对象间的依赖关系;其它的行为对象模式常将行为封装封装在一个对象中,并将请求指派给它,Strategy模式将算法封装在对象中,这样可以方面的改变和指定一个对象所使用的算法;Command模式将请求封装在对象中,这样它就可以作为参数来传递,已可以存储在历史列表中或以其它方式使用;State模式封装一个对象的状态,使得当这个对象的状态对象变化时,该对象可改变它的行为;Visitor模式封装分布于多个类之间的行为;而Iterator模式则抽象了访问和遍历一个集合中对象的方式。