Php设计模式(三):行为型模式 part 2

发布时间:2020-07-27 19:28:11 作者:ucaicn
来源:网络 阅读:307

<接上一篇>


5、中介者模式(Mediator):

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

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

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

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

代码实现:


<?php
 
/**
 * 优才网公开课示例代码
 *
 * 中介者模式 Mediator
 *
 * @author 优才网全栈工程师教研组
 * @seehttp://www.ucai.cn
 */
 
 
function output($string) {
    echo   $string . "\n";
}
 
 
 
 
abstract class Mediator { // 中介者角色
    abstractpublic function send($message,$colleague); 
} 
 
abstract class Colleague { // 抽象对象
    private$_mediator = null; 
    publicfunction __construct($mediator) { 
       $this->_mediator = $mediator; 
    } 
    publicfunction send($message) { 
       $this->_mediator->send($message,$this); 
    } 
    abstractpublic function notify($message); 
} 
 
class ConcreteMediator extends Mediator { // 具体中介者角色
    private$_colleague1 = null; 
    private$_colleague2 = null; 
    publicfunction send($message,$colleague) { 
       if($colleague == $this->_colleague1) { 
           $this->_colleague1->notify($message); 
        } else{ 
           $this->_colleague2->notify($message); 
        } 
    }
    publicfunction set($colleague1,$colleague2) { 
       $this->_colleague1 = $colleague1; 
       $this->_colleague2 = $colleague2; 
    } 
} 
 
class Colleague1 extends Colleague { // 具体对象角色
    publicfunction notify($message) {
       output(sprintf('Colleague-1: %s', $message));
    } 
} 
 
class Colleague2 extends Colleague { // 具体对象角色
    publicfunction notify($message) { 
       output(sprintf('Colleague-2: %s', $message));
    } 
} 
 
 
 
class Client { 
      
    publicstatic function test(){  
 
        //client
       $objMediator = new ConcreteMediator(); 
        $objC1= new Colleague1($objMediator); 
        $objC2= new Colleague2($objMediator); 
       $objMediator->set($objC1,$objC2); 
       $objC1->send("to c2 from c1"); 
       $objC2->send("to c1 from c2"); 
 
    }  
      
}  
  
Client::test();


6、状态模式(State) :

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

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

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

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

代码实现:


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

 

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


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

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

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

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

       应用场景:处理多种请求

代码实现:


<?php
 
/**
 * 优才网公开课示例代码
 *
 * 职责链模式 Chain of Responsibility
 *
 * @author 优才网全栈工程师教研组
 * @seehttp://www.ucai.cn
 */
 
function output($string) {
    echo    $string . "\n";
}
 
/** 
 * 加入在公司里,如果你的请假时间小于0.5天,那么只需要向leader打声招呼就OK了。
  如果0.5<=请假天数<=3天,需要先leader打声招呼,然后部门经理签字。
  如果3<请假天数,需要先leader打声招呼,然后到部门经理签字,最后总经经理确认签字,
    如果请假天数超过10天,是任何人都不能批准的。
 */ 
 
  
/** 
 * 抽象处理者角色(Handler:Approver):定义一个处理请求的接口,和一个后继连接(可选) 
 * 
 */  
abstract class Handler 
{  
 
    protected$_handler = null;  
    protected$_handlerName = null;  
      
    publicfunction setSuccessor($handler)  
    {  
       $this->_handler = $handler;  
    }  
      
   protected  function_success($request)  
    {  
       output(sprintf("%s's request was passed",$request->getName())); 
        returntrue;  
    }  
    abstractfunction handleRequest($request);  
}  
 
/** 
 * 具体处理者角色(ConcreteHandler:President):处理它所负责的请求,可以访问后继者,如果可以处理请求则处理,否则将该请求转给他的后继者。
 * 
 */  
class ConcreteHandlerLeader extends Handler  
{  
    function__construct($handlerName){  
       $this->_handlerName = $handlerName; 
    }  
    publicfunction handleRequest($request)  
    {  
       if($request->getDay() < 0.5) { 
           output(sprintf('%s was told', $this->_handlerName));       // 已经跟leader招呼了
           return $this->_success($request); 
        }   
        if($this->_handler instanceof Handler) { 
           return $this->_handler->handleRequest($request);  
        }  
    }  
}  
/** 
 * Manager 
 * 
 */  
class ConcreteHandlerManager extends Handler  
{  
    function__construct($handlerName){  
       $this->_handlerName = $handlerName; 
    }  
      
    publicfunction handleRequest($request)  
    {  
        if(0.5<= $request->getDay() && $request->getDay()<=3) {  
            output(sprintf('%s signed',$this->_handlerName));       // 部门经理签字
           return $this->_success($request); 
        }   
        if($this->_handler instanceof Handler) { 
           return $this->_handler->handleRequest($request);  
        }  
    }  
 
}  
 
class ConcreteHandlerGeneralManager extendsHandler  
{  
    function__construct($handlerName){  
       $this->_handlerName = $handlerName; 
    }  
      
    publicfunction handleRequest($request)  
    {  
        if(3< $request->getDay() && $request->getDay() < 10){  
           output(sprintf('%s signed', $this->_handlerName));       // 总经理签字
           return $this->_success($request); 
        }  
        if($this->_handler instanceof Handler) { 
           return $this->_handler->handleRequest($request);  
        } else{
           output(sprintf('no one can approve request more than 10 days'));
        }
    }  
 
}  
 
/** 
 * 请假申请
 * 
 */  
class Request 
{  
    private$_name;  
    private$_day;  
    private$_reason;  
  
    function__construct($name= '', $day= 0, $reason = ''){ 
       $this->_name = $name;  
       $this->_day = $day;  
       $this->_reason = $reason;  
    }  
      
    publicfunction setName($name){  
       $this->_name = $name;  
    }  
 
    publicfunction getName(){  
       return  $this->_name;  
    }  
      
    publicfunction setDay($day){  
       $this->_day = $day;  
    }  
 
    publicfunction getDay(){  
       return  $this->_day ;  
    }  
      
    publicfunction setReason($reason ){  
        $this->_reason = $reason;  
    }  
 
    publicfunction getReason( ){  
       return  $this->_reason;  
    }  
}  
  
  
class Client { 
      
    publicstatic function test(){  
          
        $leader= new ConcreteHandlerLeader('leader');  
       $manager = new ConcreteHandlerManager('manager');  
       $generalManager = newConcreteHandlerGeneralManager('generalManager');  
          
        //请求实例  
       $request = new Request('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
 */
 
 
function output($string) {
    echo    $string . "\n";
}
 
//策略基类接口
 
interface IStrategy {
    publicfunction OnTheWay();
}
 
class WalkStrategy implements IStrategy {
    publicfunction OnTheWay() {
       output( '在路上步行');
    }
}
 
class RideBickStrategy implements IStrategy {
    publicfunction OnTheWay() {
       output( '在路上骑自行车');
    }
}
 
class CarStrategy implements IStrategy {
    publicfunction OnTheWay() {
       output( '在路上开车');
    }
}
 
//选择策略类Context
class Context {
    public functionfind($strategy) {
       $strategy->OnTheWay();
    }
}
 
class Client { 
      
    publicstatic function test(){  
 
       $travel = new Context();
       $travel->find(new WalkStrategy());
       $travel->find(new RideBickStrategy());
        $travel->find(new CarStrategy());
 
    }  
      
}  
  
Client::test();


 

 

已知模式

1、备忘录模式(Memento):

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

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

        弊端:消耗资源

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

代码实现:


<?php
 
/**
 * 优才网公开课示例代码
 *
 * 备忘录模式 Memento
 *
 * @author 优才网全栈工程师教研组
 * @seehttp://www.ucai.cn
 */
 
function output($string) {
    echo    $string . "\n";
}
 
 
class Originator { // 发起人(Originator)角色
    private$_state;
    publicfunction __construct() {
       $this->_state = '';
    }
    publicfunction createMemento() { // 创建备忘录
        returnnew Memento($this->_state);
    }
    publicfunction restoreMemento(Memento $memento) { // 将发起人恢复到备忘录对象记录的状态上
       $this->_state = $memento->getState();
    }
    publicfunction setState($state) { $this->_state = $state; } 
    publicfunction getState() { return $this->_state; }
    publicfunction showState() {
       output($this->_state);
    }
 
}
 
class Memento { // 备忘录(Memento)角色
    private$_state;
    publicfunction __construct($state) {
       $this->setState($state);
    }
    publicfunction getState() { return $this->_state; } 
    publicfunction setState($state) { $this->_state = $state;}
}
 
class Caretaker { // 负责人(Caretaker)角色
    private$_memento;
    public functiongetMemento() { return $this->_memento; } 
    publicfunction setMemento(Memento $memento) { $this->_memento = $memento; }
}
 
class Client { 
      
    publicstatic function test(){  
 
        $org =new Originator();
       $org->setState('open');
       $org->showState();
 
        /* 创建备忘 */
       $memento = $org->createMemento();
 
        /* 通过Caretaker保存此备忘 */
       $caretaker = new Caretaker();
       $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) {
        thrownew Exception('SQL 1 update failed');
    }
 
    $succ   = $db->exec($sql_2);
    if(!$succ) {
        thrownew Exception('SQL 2 update failed');
    }
 
    $succ   = $db->exec($sql_3);
    if(!$succ) {
        throw newException('SQL 3 update failed');
    }
 
   $db->commit();
 
} catch (Exception $exp) {
 
   $db->rollBack();
 
}

深度模式


1、解释器模式(Interpreter):

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

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

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

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


2、访问者模式(Visitor):

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

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

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

       应用场景:排队,排号


三、总结

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


推荐阅读:
  1. 设计模式-行为型
  2. Php设计模式(三):行为型模式 part1

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php 设计模式 行为模式

上一篇:64ES6_流程控制

下一篇:selectI实现I/O复用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》