php设计模式入门-命令模式

来源:互联网 发布:win10很卡怎么优化 编辑:程序博客网 时间:2024/05/21 07:02

场景:某家公司需要生产一款遥控器,可以控制家用电器的开关,该开关拥有五列两排按键,现在需要我们为这个遥控器编写程序来实现相应功能。

解决方案1看到这样的需求场景,我们第一个想法可能是模拟jsonclick事件,每个按钮按下时触发事件,js调用后台程序执行相应逻辑。

弊端:这样的做法其实是一种硬编码。即各按键一次绑定永不能修改,在这个以人为本尊重用户体验的大环境下这十分的不人性化。

接下我们来看看命令模式怎样为我们解决这个难题:

命令模式的uml类图如下所示:


初看这幅uml图,其实我也觉得乱也没看懂,不过没关系,我们用代码来说明,先看第一个初始版本的设计:


command接口:Command.php

<?phpinterface  Command{    public function execute();}

电灯类:Light.php

<?phpclass Light{    public function on(){        echo "the light is on <br/>";    }        public function off(){        echo "the light is off <br/>";    }}

开灯命令类:LightOffCommand.php

<?phprequire_once 'Command.php';class LightOffCommand implements Command{    private $_light;    public function __construct(Light $light){        $this->_light = $light;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        $this->_light->off();    }}

关灯命令类:LightOnCommand.php

<?phprequire_once 'Command.php';class LightOnCommand implements Command{    private $_light;    public function __construct(Light $light){        $this->_light = $light;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        $this->_light->on();    }}

遥控器类:RemoteController.php

<?phpclass RemoteController{    private $_command;        public function setCommand(Command $command){        $this->_command = $command;    }         public function bottonWasPressed(){        $this->_command->execute();    }}

入口文件:index.php

<?php//初尝命令模式require_once 'Light.php';require_once 'LightOffCommand.php';require_once 'LightOnCommand.php';require_once 'RemoteController.php';$light = new Light();$lightOnCommand = new LightOnCommand($light);$lightOffCommand = new LightOffCommand($light);$remoteController = new RemoteController();$remoteController->setCommand($lightOnCommand);$remoteController->bottonWasPressed();$remoteController->setCommand($lightOffCommand);$remoteController->bottonWasPressed();

可以看出比起硬编码,使用命令模式实现该需求具有更强的灵活性和可变性。

现在我们根据以上的代码再来解释一下上面的uml类图:

Command:声明执行操作的接口。调用接收者相应的操作,以实现执行的方法Execute,对应示例代码中的command.php。

ConcreteCommand:创建一个具体命令对象并设定它的接收者。通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。对应示例代码中的LightOffCommand.php和LightOnCommand.php

Invoker:要求该命令执行这个请求。通常会持有命令对象,可以持有很多的命令对象。对应示例代码中的RemoteController.php

Receiver:知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者,只要它能够实现命令要求实现的相应功能。 对应示例代码中的Light.php

Client:建具体的命令对象,并且设置命令对象的接收者。真正使用命令的客户端是从Invoker来触发执行。 对应示例代码中的index.php


假设有了新的需求,遥控器需要拥有撤销功能,其实很简单,我们只需要在每一个ConcreteCommand类中加上一个undo方法就行,我们现在就来实现这个功能,代码如下:

命令接口:Command.php

<?phpinterface  Command{    public function execute();}

关灯命令类:LightOffCommand.php

<?phprequire_once 'Command.php';class LightOffCommand implements Command{    private $_light;    public function __construct(Light $light){        $this->_light = $light;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        $this->_light->off();    }        public function undo()    {        // TODO Auto-generated method stub        $this->_light->on();    }}

开灯命令类:LightOnCommand.php

<?phprequire_once 'Command.php';class LightOnCommand implements Command{    private $_light;    public function __construct(Light $light){        $this->_light = $light;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        $this->_light->on();    }        public function undo()    {        // TODO Auto-generated method stub        $this->_light->off();    }}


电灯类:Light.php

<?phpclass Light{    public function on(){        echo "the light is on <br/>";    }        public function off(){        echo "the light is off <br/>";    }}

关闭电风扇命令:CellingFanDownCommand.php

<?phprequire_once 'Command.php';class CellingFanDownCommand implements Command{    private $_celling_fan;    public function __construct(CellingFan $cellingFan){        $this->_celling_fan = $cellingFan;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        $this->_celling_fan->down();    }        public function undo()    {        // TODO Auto-generated method stub        $this->_celling_fan->up();    }}

开启电风扇命令:CellingFanUpCommand.php

<?phprequire_once 'Command.php';class CellingFanUpCommand implements Command{    private $_celling_fan;    public function __construct(CellingFan $cellingFan){        $this->_celling_fan = $cellingFan;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        $this->_celling_fan->up();    }    public function undo()    {        // TODO Auto-generated method stub        $this->_celling_fan->down();    }}


电风扇类:CellingFan.php
<?phpclass CellingFan{    public function up(){        echo "the cellingfan is up <br/>";    }        public function down(){         echo "the cellingfan is down <br/>";    }}

开车库门命令类:GarageDoorOpenCommand.php

<?phprequire_once 'Command.php';class GarageDoorOpenCommand implements Command{    private $_garage_door;    public function __construct(GarageDoor $garageDoor){        $this->_garage_door = $garageDoor;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        $this->_garage_door->open();    }        public function undo()    {        // TODO Auto-generated method stub        $this->_garage_door->close();    }}

关车库门命令:GarageDoorCloseCommand.php

<?phprequire_once 'Command.php';class GarageDoorCloseCommand implements Command{    private $_garage_door;    public function __construct(GarageDoor $garageDoor){        $this->_garage_door = $garageDoor;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        $this->_garage_door->close();    }        public function undo()    {        // TODO Auto-generated method stub        $this->_garage_door->open();    }}
车库门类:GarageDoor.php
<?phpclass GarageDoor{    public function open(){        echo "the garagedoor is open <br/>";    }        public function close(){        echo "the garagedoor is close <br/>";    }}

什么都不做的命令类:NoCommand.php

<?phprequire_once 'Command.php';class NoCommand implements Command{        public function execute()    {            }}

遥控器类:RemoteController.php

<?phprequire_once 'NoCommand.php';class RemoteController{    private $_onCommand = array();    private $_offCommand = array();    private $_undoCommand;    public function __construct()    {        for ($i = 1; $i < 7; $i ++) {            $this->_onCommand[$i] = new NoCommand();            $this->_offCommand[$i] = new NoCommand();        }        $this->_undoCommand = new NoCommand();    }    public function setOnAndOffCommand($key, Command $onCommand, Command $offCommand)    {        $this->_onCommand[$key] = $onCommand;        $this->_offCommand[$key] = $offCommand;    }    public function onBottonWasPressed($key)    {        $this->_onCommand[$key]->execute();        $this->_undoCommand = $this->_onCommand[$key];    }    public function offBottonWasPressed($key)    {        $this->_offCommand[$key]->execute();        $this->_undoCommand = $this->_offCommand[$key];    }        public function undoBottonWasPressed()    {        $this->_undoCommand->undo();    }}

入口文件:index.php

<?php//初尝命令模式require_once 'Light.php';require_once 'LightOffCommand.php';require_once 'LightOnCommand.php';require_once 'GarageDoor.php';require_once 'GarageDoorCloseCommand.php';require_once 'GarageDoorOpenCommand.php';require_once 'CellingFan.php';require_once 'CellingFanDownCommand.php';require_once 'CellingFanUpCommand.php';require_once 'RemoteController.php';$light = new Light();$lightOnCommand = new LightOnCommand($light);$lightOffCommand = new LightOffCommand($light);$garageDoor = new GarageDoor();$garageDoorOpenCommand = new GarageDoorOpenCommand($garageDoor);$garageDoorCloseCommand = new GarageDoorCloseCommand($garageDoor);$cellingFan = new CellingFan();$cellingFanUpCommand = new CellingFanUpCommand($cellingFan);$cellingFanDownCommand = new CellingFanDownCommand($cellingFan);$remoteController = new RemoteController();$remoteController->setOnAndOffCommand(0, $lightOnCommand, $lightOffCommand);$remoteController->setOnAndOffCommand(1, $garageDoorOpenCommand, $garageDoorCloseCommand);$remoteController->setOnAndOffCommand(2, $cellingFanUpCommand, $cellingFanDownCommand);$remoteController->onBottonWasPressed(0);$remoteController->offBottonWasPressed(0);$remoteController->onBottonWasPressed(1);$remoteController->offBottonWasPressed(1);$remoteController->onBottonWasPressed(2);$remoteController->offBottonWasPressed(2);
上面的代码中出现了一个NoCommand.php,如果没有设计这个类,当我们试图去调用没有被声明的命令类时,程序会报错,比如说我们去调用
$remoteController->onBottonWasPressed(3);
因为并未对键值为3的$_onCommand进行赋值,程序将会报错,而现在初始化时每个键值被赋予为NoCommand命令类,就可以规避这种情形下的报错


我们再扩展一下,如果用户希望可以一键执行打开点电灯、打开风扇、打开车库门这一系列的操作怎么办呢?我们可以设计一组宏命令绑定在遥控器的某个按钮上供用户使用,具体实现代码如下所示:

宏命令类:MacroCommand.php

<?phprequire_once 'Command.php';class MacroCommand implements Command{    private $_commands;        public function __construct(array $commands){        $this->_commands = $commands;    }/* (non-PHPdoc)     * @see Command::execute()     */    public function execute()    {        // TODO Auto-generated method stub        foreach ($this->_commands as $command){            $command->execute();        }    }}

入口文件index.php变更为:

<?php// 初尝命令模式require_once 'Light.php';require_once 'LightOffCommand.php';require_once 'LightOnCommand.php';require_once 'GarageDoor.php';require_once 'GarageDoorCloseCommand.php';require_once 'GarageDoorOpenCommand.php';require_once 'CellingFan.php';require_once 'CellingFanDownCommand.php';require_once 'CellingFanUpCommand.php';require_once 'RemoteController.php';require_once 'MacroCommand.php';$light = new Light();$lightOnCommand = new LightOnCommand($light);$lightOffCommand = new LightOffCommand($light);$garageDoor = new GarageDoor();$garageDoorOpenCommand = new GarageDoorOpenCommand($garageDoor);$garageDoorCloseCommand = new GarageDoorCloseCommand($garageDoor);$cellingFan = new CellingFan();$cellingFanUpCommand = new CellingFanUpCommand($cellingFan);$cellingFanDownCommand = new CellingFanDownCommand($cellingFan);$macroOnCommand = new MacroCommand(array(    $lightOnCommand,    $garageDoorOpenCommand,    $cellingFanUpCommand));$macroOffCommand = new MacroCommand(array(    $lightOffCommand,    $garageDoorCloseCommand,    $cellingFanDownCommand));$remoteController = new RemoteController();/* $remoteController->setOnAndOffCommand(0, $lightOnCommand, $lightOffCommand);$remoteController->setOnAndOffCommand(1, $garageDoorOpenCommand, $garageDoorCloseCommand);$remoteController->setOnAndOffCommand(2, $cellingFanUpCommand, $cellingFanDownCommand);$remoteController->onBottonWasPressed(0);$remoteController->undoBottonWasPressed();$remoteController->offBottonWasPressed(0);$remoteController->undoBottonWasPressed();$remoteController->onBottonWasPressed(1);$remoteController->undoBottonWasPressed();$remoteController->offBottonWasPressed(1);$remoteController->undoBottonWasPressed();$remoteController->onBottonWasPressed(2);$remoteController->undoBottonWasPressed();$remoteController->offBottonWasPressed(2);$remoteController->undoBottonWasPressed(); */$remoteController->setOnAndOffCommand(3, $macroOnCommand, $macroOffCommand);$remoteController->onBottonWasPressed(3);$remoteController->offBottonWasPressed(3);






0 0
原创粉丝点击