>백엔드 개발 >PHP 튜토리얼 >Php 디자인 패턴: 행동 패턴 (2)

Php 디자인 패턴: 행동 패턴 (2)

巴扎黑
巴扎黑원래의
2016-11-12 11:50:401048검색

344a071dd39379c1dc40427ac09918c9

4. 관찰자 모드(Observer):

발행-구독 모드라고도 하며, 주체 개체가 변경되면 이에 의존하는 많은 개체가 발생합니다. 각 관찰자 객체는 이에 대한 알림을 받고 자동으로 업데이트됩니다. 신문과 마찬가지로, 오늘 뉴스를 읽는 모든 사람은 같은 내용을 보게 될 것입니다. 다른 신문이 발행되는 경우에도 마찬가지입니다.

장점: 방송통신, 넓은 범위, 한 번의 호출로 백개의 응답에 응답할 수 있음, 그룹 운영이 용이함, "공공 소유".

단점: 그룹 내 개인이 독립적으로 운영될 수 없으며, 주문형 할당을 구현할 수 없습니다.

적용 시나리오: 여러 개체를 작동하고 동일한 작업을 수행합니다.

코드 구현:

[php] 일반 사본 보기

<?php  
  
/** 
 * 优才网公开课示例代码 
 * 
 * 观察者模式 Observer 
 * 
 * @author 优才网全栈工程师教研组 
 * @see http://www.ucai.cn 
 */  
  
function output($string) {  
    echo    $string . "\n";  
}  
  
  
//订单数据对象简单模拟,这个是实际需要被观察的对象(Subject),但是我们将其独立,然后  
//通过构造方法传入到我们模式中的Subject中,这样使具体业务更加独立  
class Order{  
    //订单号  
    private $id = &#39;&#39;;  
  
    //用户ID  
    private $userId = &#39;&#39;;  
  
    //用户名  
    private $userName = &#39;&#39;;  
  
    //价格  
    private $price = &#39;&#39;;  
  
    //下单时间  
    private $orderTime = &#39;&#39;;  
  
    //订单数据填充简单模拟,实际应用中可能会读取用户表单输入并处理  
    public function __set($name, $value){  
        if (isset($this->$name)){  
            $this->$name = $value;  
        }  
    }  
  
    //获取订单属性  
    public function __get($name){  
        if (isset($this->$name)){  
            return $this->$name;  
        }  
        return "";  
    }  
}  
  
//假设的DB类,便于测试,实际会存入真实数据库  
class FakeDB{  
    public function save($data){  
        return true;  
    }  
}  
  
  
class Client {  
      
    public static function test() {  
  
        //初始化一个订单数据  
        $order = new Order();  
        $order->id = 1001;  
        $order->userId = 9527;  
        $order->userName = "God";  
        $order->price = 20.0;  
        $order->orderTime = time();  
  
        //向数据库保存订单  
        $db = new FakeDB();  
        $result = $db->save($order);  
        if ($result){  
  
            //实际应用可能会写到日志文件中,这里直接输出  
            output( "[OrderId:{$order->id}] [UseId:{$order->userId}] [Price:{$order->price}]" );  
  
            //实际应用会调用邮件发送服务如sendmail,这里直接输出  
            output( "Dear {$order->userName}: Your order {$order->id} was confirmed!" );  
  
            //实际应用会调用邮件发送服务如sendmail,这里直接输出  
            output( "Dear Manager: User {$order->userName}(ID:{$order->userId}) submitted a new order {$order->id}, please handle it ASAP!" );  
  
        }  
  
    }  
  
}  
  
Client::test();

<?php  
  
/** 
 * 优才网公开课示例代码 
 * 
 * 观察者模式 Observer 
 * 
 * @author 优才网全栈工程师教研组 
 * @see http://www.ucai.cn 
 */  
  
function output($string) {  
    echo    $string . "\n";  
}  
  
  
//订单数据对象简单模拟,这个是实际需要被观察的对象(Subject),但是我们将其独立,然后  
//通过构造方法传入到我们模式中的Subject中,这样使具体业务更加独立  
class Order{  
    //订单号  
    private $id = &#39;&#39;;  
  
    //用户ID  
    private $userId = &#39;&#39;;  
  
    //用户名  
    private $userName = &#39;&#39;;  
  
    //价格  
    private $price = &#39;&#39;;  
  
    //下单时间  
    private $orderTime = &#39;&#39;;  
  
    //订单数据填充简单模拟,实际应用中可能会读取用户表单输入并处理  
    public function __set($name, $value){  
        if (isset($this->$name)){  
            $this->$name = $value;  
        }  
    }  
  
    //获取订单属性  
    public function __get($name){  
        if (isset($this->$name)){  
            return $this->$name;  
        }  
        return "";  
    }  
}  
  
//被观察者, 负责维护观察者并在变化发生是通知观察者  
class OrderSubject implements SplSubject {  
    private $observers;  
    private $order;  
  
    public function __construct(Order $order) {  
        $this->observers = new SplObjectStorage();  
        $this->order = $order;  
    }  
  
    //增加一个观察者  
    public function attach(SplObserver $observer) {  
        $this->observers->attach($observer);  
    }  
  
    //移除一个观察者  
    public function detach(SplObserver $observer) {  
        $this->observers->detach($observer);  
    }  
  
    //通知所有观察者  
    public function notify() {  
        foreach ($this->observers as $observer) {  
            $observer->update($this);  
        }  
    }  
  
    //返回主体对象的具体实现,供观察者调用  
    public function getOrder() {  
        return $this->order;  
    }  
}  
  
//记录业务数据日志 (ActionLogObserver),实际可能还要抽象一层以处理不同的Action(业务操作),这里省略  
class ActionLogObserver implements SplObserver{  
    public function update(SplSubject $subject) {  
         $order = $subject->getOrder();  
         //实际应用可能会写到日志文件中,这里直接输出  
         output( "[OrderId:{$order->id}] [UseId:{$order->userId}] [Price:{$order->price}]" );  
    }  
}  
  
//给用户发送订单确认邮件 (UserMailObserver)  
class UserMailObserver implements SplObserver{  
    public function update(SplSubject $subject) {  
         $order = $subject->getOrder();  
         //实际应用会调用邮件发送服务如sendmail,这里直接输出  
         output( "Dear {$order->userName}: Your order {$order->id} was confirmed!" );  
    }  
}  
  
//给管理人员发订单处理通知邮件 (AdminMailObserver)  
class AdminMailObserver implements SplObserver{  
    public function update(SplSubject $subject) {  
         $order = $subject->getOrder();  
         //实际应用会调用邮件发送服务如sendmail,这里直接输出  
         output( "Dear Manager: User {$order->userName}(ID:{$order->userId}) submitted a new order {$order->id}, please handle it ASAP!" );  
    }  
}  
  
//假设的DB类,便于测试,实际会存入真实数据库  
class FakeDB{  
    public function save($data){  
        return true;  
    }  
}  
  
  
class Client {  
      
    public static function test() {  
  
        //初始化一个订单数据  
        $order = new Order();  
        $order->id = 1001;  
        $order->userId = 9527;  
        $order->userName = "God";  
        $order->price = 20.0;  
        $order->orderTime = time();  
  
        //绑定观察者  
        $subject = new OrderSubject($order);  
        $actionLogObserver = new ActionLogObserver();  
        $userMailObserver = new UserMailObserver();  
        $adminMailObserver = new AdminMailObserver();  
        $subject->attach($actionLogObserver);  
        $subject->attach($userMailObserver);  
        $subject->attach($adminMailObserver);  
        //向数据库保存订单  
        $db = new FakeDB();  
        $result = $db->save($order);  
        if ($result){  
            //通知观察者  
            $subject->notify();  
        }  
  
    }  
  
}  
  
Client::test();

5. 중재자 패턴(Mediator):

중재 개체를 사용하여 일련의 개체 상호 작용을 캡슐화하면 개체가 서로를 명시적으로 참조할 필요가 없습니다. . 우체국과 마찬가지로, 우편물을 보내는 사람과 수취인은 멀리까지 이동할 필요 없이 우체국을 통해서만 갈 수 있습니다.

이점: 객체 간의 관계를 단순화하고 하위 클래스 생성을 줄입니다.

단점: 중간 개체가 매우 복잡해질 수 있으며 시스템 유지 관리가 어려울 수 있습니다.

적용 시나리오: 디스플레이 없이 상호 작용을 설정합니다.

코드 구현:

[php] 일반 복사 보기

<?php  
  
/** 
 * 优才网公开课示例代码 
 * 
 * 中介者模式 Mediator 
 * 
 * @author 优才网全栈工程师教研组 
 * @see http://www.ucai.cn 
 */  
  
  
function output($string) {  
    echo    $string . "\n";  
}  
  
  
  
  
abstract class Mediator { // 中介者角色  
    abstract public function send($message,$colleague);   
}   
  
abstract class Colleague { // 抽象对象  
    private $_mediator = null;   
    public function __construct($mediator) {   
        $this->_mediator = $mediator;   
    }   
    public function send($message) {   
        $this->_mediator->send($message,$this);   
    }   
    abstract public function notify($message);   
}   
  
class ConcreteMediator extends Mediator { // 具体中介者角色  
    private $_colleague1 = null;   
    private $_colleague2 = null;   
    public function send($message,$colleague) {   
        if($colleague == $this->_colleague1) {   
            $this->_colleague1->notify($message);   
        } else {   
            $this->_colleague2->notify($message);   
        }   
    }  
    public function set($colleague1,$colleague2) {   
        $this->_colleague1 = $colleague1;   
        $this->_colleague2 = $colleague2;   
    }   
}   
  
class Colleague1 extends Colleague { // 具体对象角色  
    public function notify($message) {  
        output(sprintf(&#39;Colleague-1: %s&#39;, $message));  
    }   
}   
  
class Colleague2 extends Colleague { // 具体对象角色  
    public function notify($message) {   
        output(sprintf(&#39;Colleague-2: %s&#39;, $message));  
    }   
}   
  
  
  
class Client {    
        
    public static 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. 모드(상태):

객체는 상태에 따라 다른 동작을 나타냅니다. 여자친구처럼 기쁠 때는 손을 잡아주고, 슬플 때는 개를 산책시켜준다. 두 상태에서 서로 다른 동작을 보여줍니다.

이점: if 문을 피하는 것이 실용적이고, 새 상태를 추가하는 데 편리하며, 상태 전환 규칙을 캡슐화합니다.

단점: 시스템 클래스 및 개체 수가 늘어납니다.

응용 시나리오: 객체의 다양한 기능을 변환하는 데 사용됩니다.

코드 구현:

[php] 일반 사본 보기

<?php  
  
/** 
 * 优才网公开课示例代码 
 * 
 * 状态模式 State 
 * 
 * @author 优才网全栈工程师教研组 
 * @see http://www.ucai.cn 
 */  
  
function output($string) {  
    echo    $string . "\n";  
}  
  
abstract class ILift {    
  
    //电梯的四个状态    
    const OPENING_STATE = 1;  //门敞状态    
    const CLOSING_STATE = 2;  //门闭状态    
    const RUNNING_STATE = 3;  //运行状态    
    const STOPPING_STATE = 4; //停止状态;    
        
    //设置电梯的状态    
    public abstract function setState($state);    
    
    //首先电梯门开启动作    
    public abstract function open();    
    
    //电梯门有开启,那当然也就有关闭了    
    public abstract function close();    
    
    //电梯要能上能下,跑起来    
    public abstract function run();    
    
    //电梯还要能停下来  
    public abstract function stop();    
  
}    
    
/**  
 * 电梯的实现类   
 */     
class Lift extends ILift {    
  
    private $state;    
    
    public function setState($state) {    
        $this->state = $state;    
    }    
  
    //电梯门关闭    
    public function 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(&#39;Lift colse&#39;);    
  
    }    
    
    //电梯门开启    
    public function 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(&#39;Lift open&#39;);    
    }    
    ///电梯开始跑起来    
    public function 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(&#39;Lift run&#39;);    
    }    
    
    //电梯停止    
    public function 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(&#39;Lift stop&#39;);    
    }    
        
}    
  
  
  
class Client {  
      
    public static function test() {  
  
        $lift = new Lift();     
               
        //电梯的初始条件应该是停止状态     
        $lift->setState(ILift::STOPPING_STATE);     
        //首先是电梯门开启,人进去     
        $lift->open();     
               
        //然后电梯门关闭     
        $lift->close();     
               
        //再然后,电梯跑起来,向上或者向下     
        $lift->run();        
  
         //最后到达目的地,电梯挺下来     
        $lift->stop();    
  
    }  
  
}  
  
Client::test();

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


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.