Php设计模式之【命令模式Command Pattern】
2012-05-19 12:25
841 查看
【案例】
黑枣玩具公司专门生产玩具,生产的玩具不限于狗、猫、狮子等四肢动物。每个玩具身上有两个按钮,分别支持两个操作——“张嘴”与“闭嘴”。
<代码实现>
【系统要升级】
遥控科技发展,在玩具上的两个控制按钮就不再要了。黑枣玩具公司想要实现手机遥控玩具,
1. 通过设置手机,手机可以与不同玩具连接实现控制
2. 手机星号(*)按钮按键为“张嘴”控制按键
3. 手机井号(#)按钮按键为“闭嘴”控制按键
【分析OOA】
相对于旧版玩具,新的玩具需要实现玩具实体与控制体分离,即玩具狗身上不再有按钮,按钮要分离出来。也其实也是典型的命令模式场景。我们结合一个命令模式分析本案例。
【设计OOD】
<UML>
【说明】
命令模式是有5个角色来组成,分别为
1. 命令角色(Command):声明执行操作的接口。通常代码中表现为接口或者抽象类
在本例中可为玩具命令Command接口
2. 具体命令角色(Concrete Command):将一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现命令角色声明的执行操作的接口。
在本例中为DogOpenMouthCommand、DogCloseMouthCommand、CatOpenMouthCommand、CatCloseMouthCommand的实例对象。
3. 请求者角色(Invoker):谁去调用命令对象执行这个请求。
谁来让狗猫张嘴闭嘴?当然是手机了。
4. 接收者角色(Receiver):知道如何实施与执行一个请求相关的操作。
在这里接收者为狗或者猫,即Receiver类的一个实例。Receiver们都实现了openMouth张嘴、closeMouth闭嘴操作。
5. 客户角色(Client):创建一个具体命令对象(并可以设定它的接收者)。
这里是手机玩家,即Client类的一个实例。
【编程 OOP:
<代码>
1. 先来看看命令接口的定义,示例代码如下:
2. 再来看看具体的命令实现对象,示例代码如下:
3. 再来看看接收者对象的实现示意,示例代码如下:
4. 接下来看看Invoker对象,示例代码如下:
5. 再来看看Client的实现,注意这个不是我们通常意义上的测试客户端,主要功能是要创建命令对象并设定它的接收者,因此这里并没有调用执行的代码,示例代码如下:
【测试用例Test Case】
<代码>
【输出】
【小结】
命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。而在上面的举例中并没有体现出来。其实命令模式之所以能够支持这种操作,完全得益于在请求者与接收者之间添加了中间角色。
为了实现undo功能,首先需要一个历史列表来保存已经执行过的具体命令角色对象;修改具体命令角色中的执行方法,使它记录更多的执行细节,并将自己放入历史列表中;并在具体命令角色中添加undo方法,此方法根据记录的执行细节来复原状态(很明显,首先程序员要清楚怎么来实现,因为它和execute的效果是一样的)。
命令模式还有一个常见的用法就是执行事务操作。这就是为什么命令模式还叫做事务模式的原因吧。它可以在请求被传递到接收者角色之前,检验请求的正确性,甚至可以检查和数据库中数据的一致性,而且可以结合组合模式的结构,来一次执行多个命令。
使用命令模式不仅仅可以解除请求者和接收者之间的耦合,而且可以用来做批处理操作,这完全可以发挥你自己的想象——请求者发出的请求到达命令角色这里以后,先保存在一个列表中而不执行;等到一定的业务需要时,命令模式再将列表中全部的操作逐一执行。
********************************************
* 作者:叶文涛
* 标题:Php设计模式之【命令模式Command Pattern】
* 参考:
*《设计模式:可复用面向对象软件基础 》(美)Erich Gamma 等著
*《Head First设计模式》Eric Freeman等著
*《PHP设计模式》Aaron Saray等著,梁志敏等译(PS:翻译的是狗屁水平)
******************转载请注明网址来源 ***************
黑枣玩具公司专门生产玩具,生产的玩具不限于狗、猫、狮子等四肢动物。每个玩具身上有两个按钮,分别支持两个操作——“张嘴”与“闭嘴”。
<代码实现>
<?php /** * 所有玩具需要实现的动作接口 */ interface Toy { /** * 玩具张嘴动作 * @abstract * @return mixed */ public function openMouth(); /** * 玩具闭嘴动作 * @abstract * @return mixed */ public function closeMouth(); } /** * 所有玩具上的按钮被按下后需要实现的动作接口 */ interface Ctrl { /** * 按钮1被按下 * @abstract * @return mixed */ public function Bt1Pressed(); /** * 按钮2被按下 * @abstract * @return mixed */ public function Bt2Pressed(); } /** *狗类玩具 */ class Dog implements Toy,Ctrl { public function openMouth() { echo "Dog Open Mouth\n"; } public function closeMouth() { echo "Dog Close Mouth\n"; } public function Bt1Pressed() { $this->openMouth(); } public function Bt2Pressed() { $this->closeMouth(); } } class testDriver { public function run() { //新建一个狗玩具 $toy = new Dog(); //狗玩具按钮1被按下 $toy->Bt1Pressed(); //狗玩具按钮2被按下 $toy->Bt2Pressed(); } } $test = new testDriver(); $test->run();<输出>
【系统要升级】
遥控科技发展,在玩具上的两个控制按钮就不再要了。黑枣玩具公司想要实现手机遥控玩具,
1. 通过设置手机,手机可以与不同玩具连接实现控制
2. 手机星号(*)按钮按键为“张嘴”控制按键
3. 手机井号(#)按钮按键为“闭嘴”控制按键
【分析OOA】
相对于旧版玩具,新的玩具需要实现玩具实体与控制体分离,即玩具狗身上不再有按钮,按钮要分离出来。也其实也是典型的命令模式场景。我们结合一个命令模式分析本案例。
【设计OOD】
<UML>
【说明】
命令模式是有5个角色来组成,分别为
1. 命令角色(Command):声明执行操作的接口。通常代码中表现为接口或者抽象类
在本例中可为玩具命令Command接口
2. 具体命令角色(Concrete Command):将一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现命令角色声明的执行操作的接口。
在本例中为DogOpenMouthCommand、DogCloseMouthCommand、CatOpenMouthCommand、CatCloseMouthCommand的实例对象。
3. 请求者角色(Invoker):谁去调用命令对象执行这个请求。
谁来让狗猫张嘴闭嘴?当然是手机了。
4. 接收者角色(Receiver):知道如何实施与执行一个请求相关的操作。
在这里接收者为狗或者猫,即Receiver类的一个实例。Receiver们都实现了openMouth张嘴、closeMouth闭嘴操作。
5. 客户角色(Client):创建一个具体命令对象(并可以设定它的接收者)。
这里是手机玩家,即Client类的一个实例。
【编程 OOP:
<代码>
1. 先来看看命令接口的定义,示例代码如下:
/** * 命令接口 */ interface Command { /** * 执行命令对应的操作 */ public function execute(); }
2. 再来看看具体的命令实现对象,示例代码如下:
/** * 具体的命令实现对象,示例代码如下: */ class OpenMouthCommand implements Command { /** * 持有相应的接收者对象 */ private $receiver; /** * 示意,命令对象可以有自己的状态 */ private $mouthstate = 0; /** * 构造方法,传入相应的接收者对象 * @param receiver 相应的接收者对象 */ public function __construct(Receiver $receiver) { $this->receiver = $receiver; } public function execute() { //通常会转调接收者对象的相应方法,让接收者来真正执行功能 $this->receiver->openMouth(); } } class CloseMouthCommand implements Command { private $receiver; private $mouthstate = 0; public function __construct(Receiver $receiver) { $this->receiver = $receiver; } public function execute() { $this->receiver->closeMouth(); } }
3. 再来看看接收者对象的实现示意,示例代码如下:
/** * 接收者对象超类 */ abstract class Receiver { /** * 示意方法1,真正执行命令相应的操作 * 在本案例中实现张嘴操作 */ abstract function openMouth(); /** * 示意方法2,真正执行命令相应的操作 * 在本案例中实现闭嘴操作 */ abstract function closeMouth(); } /** * 接收者对象:狗 */ class DogReceiver extends Receiver { public function openMouth() { echo "Dog open Mouth\n"; } public function closeMouth() { echo "Dog close Mouth\n"; } } /** * 接收者对象:猫 */ class CatReceiver extends Receiver { public function openMouth() { echo "Cat open Mouth\n"; } public function closeMouth() { echo "Cat close Mouth\n"; } }
4. 接下来看看Invoker对象,示例代码如下:
/** * 调用者 */ class PhoneInvoker { /** * 持有命令对象 */ private $_OpenMouthCommand = null; private $_CloseMouthComand = null; /** * 设置调用者持有的命令对象 * @param command 命令对象 */ public function setCommand($opencommand, $closecommand) { $this->_OpenMouthCommand = $opencommand; $this->_CloseMouthComand = $closecommand; } /** * 示意方法,要求命令执行请求 */ public function runBtStarPressed() { $this->_OpenMouthCommand->execute(); } public function runBtHashPressed() { $this->_CloseMouthComand->execute(); } }
5. 再来看看Client的实现,注意这个不是我们通常意义上的测试客户端,主要功能是要创建命令对象并设定它的接收者,因此这里并没有调用执行的代码,示例代码如下:
class Client { protected $receiver; protected $invoker; //把手机跟玩具连接起来 public function linkToyAndPhone($receiver, $invoker) { $this->receiver = $receiver; $this->invoker = $invoker; $command1 = new OpenMouthCommand($this->receiver); $command2 = new CloseMouthCommand($this->receiver); //创建Invoker,把命令对象设置进去 $this->invoker->setCommand($command1, $command2); } //按下手机*键 public function pressBtStar() { $this->invoker->runBtStarPressed(); } //按下手机#键 public function pressBtHash() { $this->invoker->runBtHashPressed(); } }
【测试用例Test Case】
<代码>
class testDriver { public function run() { //新建一个玩家 $client = new Client(); //新建一个狗玩具 $dog = new DogReceiver(); //新建一个猫玩具 $cat = new CatReceiver(); //新建一部手机控制端 $invoker = new PhoneInvoker(); //玩家把手机连上狗玩具 $client->linkToyAndPhone($dog, $invoker); //按下手机*键 $client->pressBtHash(); //按下手机#键 $client->pressBtStar(); //玩家把手机连上猫玩具 $client->linkToyAndPhone($cat, $invoker); //按下手机#键 $client->pressBtHash(); //按下手机*键 $client->pressBtStar(); } } $test = new testDriver(); $test->run();
【输出】
【小结】
命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。而在上面的举例中并没有体现出来。其实命令模式之所以能够支持这种操作,完全得益于在请求者与接收者之间添加了中间角色。
为了实现undo功能,首先需要一个历史列表来保存已经执行过的具体命令角色对象;修改具体命令角色中的执行方法,使它记录更多的执行细节,并将自己放入历史列表中;并在具体命令角色中添加undo方法,此方法根据记录的执行细节来复原状态(很明显,首先程序员要清楚怎么来实现,因为它和execute的效果是一样的)。
命令模式还有一个常见的用法就是执行事务操作。这就是为什么命令模式还叫做事务模式的原因吧。它可以在请求被传递到接收者角色之前,检验请求的正确性,甚至可以检查和数据库中数据的一致性,而且可以结合组合模式的结构,来一次执行多个命令。
使用命令模式不仅仅可以解除请求者和接收者之间的耦合,而且可以用来做批处理操作,这完全可以发挥你自己的想象——请求者发出的请求到达命令角色这里以后,先保存在一个列表中而不执行;等到一定的业务需要时,命令模式再将列表中全部的操作逐一执行。
********************************************
* 作者:叶文涛
* 标题:Php设计模式之【命令模式Command Pattern】
* 参考:
*《设计模式:可复用面向对象软件基础 》(美)Erich Gamma 等著
*《Head First设计模式》Eric Freeman等著
*《PHP设计模式》Aaron Saray等著,梁志敏等译(PS:翻译的是狗屁水平)
******************转载请注明网址来源 ***************
相关文章推荐
- 设计模式之七 命令模式(Command Pattern)
- C#设计模式之十四命令模式(Command Pattern)【行为型】
- 设计模式:命令模式(Command Pattern)
- Head First 设计模式 (六) 命令模式(Command pattern) C++实现
- 解读设计模式----命令模式(Command Pattern)
- 23种设计模式(14)_行为型_命令模式(Command Pattern)
- java设计模式——命令模式(Command Pattern)
- .NET设计模式(17):命令模式(Command Pattern)
- 设计模式――命令模式(Command Pattern)
- C#设计模式——命令模式(Command Pattern)
- php设计模式 Command(命令模式)
- 设计模式系列3-----C++实现命令模式(Command Pattern)
- C#设计模式之十四命令模式(Command Pattern)【行为型】
- 设计模式 —— 命令模式(Command Pattern)
- 设计模式之:命令模式(Command Pattern)
- JAVA设计模式之 命令模式【Command Pattern】
- .NET设计模式(17):命令模式(Command Pattern)
- 【设计模式】行为型模式——命令模式(Command Pattern)
- Java设计模式 Design Pattern:命令模式 Command Pattern
- 设计模式 - 命令模式(command pattern) 详解