【意图】
将一个请求封装为一个对象,从而使用你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
可变的方面是:何时,怎样满足一个请求
命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。
请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

【命令模式结构图】

PHP设计模式之命令模式_PHP设计模式

Command模式

【命令模式中主要角色】
命令(Command)角色:声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。
具体命令(ConcreteCommand)角色:定义一个接受者和行为之间的弱耦合;实现Execute()方法,负责调用接收考的相应操作。Execute()方法通常叫做执行方法。
客户(Client)角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者。
请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。
接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

【命令模式的优点】
命令模式的优点:
1、命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分离开。
2、命令类与其他任何别的类一样,可以修改和推广。
3、可以把命令对象聚合在一起,合成为合成命令。
4、可以很容易的加入新的命令类。
命令模式的缺点:可能会导致某些系统有过多的具体命令类。

【命令模式适用场景】
1、抽象出待执行的动作以参数化对象。Command模式是回调机制的一个面向对象的替代品。
2、在不同的时刻指定、排列和执行请求。
3、支持取消操作。
4、支持修改日志。
5、用构建在原语操作上的高层操作构造一个系统。Command模式提供了对事务进行建模的方法。Command有一个公共的接口,使得你可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统。

【命令模式与其它模式】
合成模式(composite模式):Composite模式可被实现宏命令
原型模式(prototype模式):如果命令类带有clone(或在之前的文章中提到的copy方法)方法,命令就可以被复制。在命令模式支持多次取消操作时可能需要用到此模式,以复制当前状态的Command对象

【命令模式PHP示例】

  1. <?php 
  2. /** 
  3.  * 命令模式 2010-08-21 sz 
  4.  * @author phppan.p#gmail.com  http://www.phppan.com                                                        
  5.  * 哥学社成员(http://www.blog-brother.com/) 
  6.  * @package design pattern 
  7.  */ 
  8.   
  9. /** 
  10.  * 命令角色 
  11.  */ 
  12. interface Command { 
  13.   
  14.     /** 
  15.      * 执行方法 
  16.      */ 
  17.     public function execute(); 
  18.   
  19. /** 
  20.  * 具体命令角色 
  21.  */ 
  22. class ConcreteCommand implements Command { 
  23.   
  24.     private $_receiver
  25.   
  26.     public function __construct(Receiver $receiver) { 
  27.         $this->_receiver = $receiver
  28.     } 
  29.   
  30.     /** 
  31.      * 执行方法 
  32.      */ 
  33.     public function execute() { 
  34.         $this->_receiver->action(); 
  35.     } 
  36.   
  37. /** 
  38.  * 接收者角色 
  39.  */ 
  40. class Receiver { 
  41.   
  42.     /* 接收者名称 */ 
  43.     private $_name
  44.   
  45.     public function __construct($name) { 
  46.         $this->_name = $name
  47.     } 
  48.   
  49.     /** 
  50.      * 行动方法 
  51.      */ 
  52.     public function action() { 
  53.         echo $this->_name, ' do action.<br />'
  54.     } 
  55.   
  56. /** 
  57.  * 请求者角色 
  58.  */ 
  59. class Invoker { 
  60.   
  61.     private $_command
  62.   
  63.     public function __construct(Command $command) { 
  64.         $this->_command = $command
  65.     } 
  66.   
  67.     public function action() { 
  68.         $this->_command->execute(); 
  69.     } 
  70.   
  71. /** 
  72.  * 客户端 
  73.  */ 
  74. class Client { 
  75.   
  76.      /** 
  77.      * Main program. 
  78.      */ 
  79.     public static function main() { 
  80.         $receiver = new Receiver('phpppan'); 
  81.         $command = new ConcreteCommand($receiver); 
  82.         $invoker = new Invoker($command); 
  83.         $invoker->action(); 
  84.     } 
  85.   
  86. Client::main(); 
  87.   
  88. ?> 

【命令模式协作】
1、Client创建一个ConcreteCommand对象并指定它的Receiver对象
2、某Invoker对象存储该ConcreteCommand对象
3、该Invoker通过调用Command对象的execute操作来提交一个请求。若该命令是可撤消的,ConcreteCommand就在执行execute操作之前存储当前状态以用于取消命令。
4、ConcreteCommand对象对调用它的Receiver的一些操作以执行该请求。

【宏命令】
在这里,我们以一个简单的增加和粘贴功能为例,将这两个命令组成一个宏命令。
我们可以新建复制命令和粘贴命令,然后将其添加到宏命令中去。
如下所示代码:

  1. <?php 
  2. /** 
  3.  * 命令模式之宏命令 2010-08-22 00:10  sz 
  4.  * @author phppan.p#gmail.com  http://www.phppan.com                                                    
  5.  * 哥学社成员(http://www.blog-brother.com/) 
  6.  * @package design pattern 
  7.  */ 
  8.   
  9. /** 
  10.  * 命令角色 
  11.  */ 
  12. interface Command { 
  13.   
  14.     /** 
  15.      * 执行方法 
  16.      */ 
  17.     public function execute(); 
  18.   
  19. /** 
  20.  * 宏命令接口 
  21.  */ 
  22. interface MacroCommand extends Command { 
  23.   
  24.     /** 
  25.      *  宏命令聚集的管理方法,可以删除一个成员命令 
  26.      * @param Command $command 
  27.      */ 
  28.     public function remove(Command $command); 
  29.   
  30.     /** 
  31.      * 宏命令聚集的管理方法,可以增加一个成员命令 
  32.      * @param Command $command 
  33.      */ 
  34.     public function add(Command $command); 
  35.   
  36.   
  37.   
  38. class DemoMacroCommand implements MacroCommand { 
  39.   
  40.     private $_commandList
  41.   
  42.     public function __construct() { 
  43.         $this->_commandList = array(); 
  44.     } 
  45.   
  46.     public function remove(Command $command) { 
  47.         $key = array_search($command$this->_commandList); 
  48.         if ($key === FALSE) { 
  49.             return FALSE; 
  50.         } 
  51.   
  52.         unset($this->_commandList[$key]); 
  53.         return TRUE; 
  54.     } 
  55.   
  56.     public function add(Command $command) { 
  57.         return array_push($this->_commandList, $command); 
  58.     } 
  59.   
  60.     public function execute() { 
  61.         foreach ($this->_commandList as $command) { 
  62.             $command->execute(); 
  63.         } 
  64.   
  65.     } 
  66.   
  67.   
  68. /** 
  69.  * 具体拷贝命令角色 
  70.  */ 
  71. class CopyCommand implements Command { 
  72.   
  73.     private $_receiver
  74.   
  75.     public function __construct(Receiver $receiver) { 
  76.         $this->_receiver = $receiver
  77.     } 
  78.   
  79.     /** 
  80.      * 执行方法 
  81.      */ 
  82.     public function execute() { 
  83.         $this->_receiver->copy(); 
  84.     } 
  85.   
  86. /** 
  87.  * 具体拷贝命令角色 
  88.  */ 
  89. class PasteCommand implements Command { 
  90.   
  91.     private $_receiver
  92.   
  93.     public function __construct(Receiver $receiver) { 
  94.         $this->_receiver = $receiver
  95.     } 
  96.   
  97.     /** 
  98.      * 执行方法 
  99.      */ 
  100.     public function execute() { 
  101.         $this->_receiver->paste(); 
  102.     } 
  103.   
  104. /** 
  105.  * 接收者角色 
  106.  */ 
  107. class Receiver { 
  108.   
  109.     /* 接收者名称 */ 
  110.     private $_name
  111.   
  112.     public function __construct($name) { 
  113.         $this->_name = $name
  114.     } 
  115.   
  116.     /** 
  117.      * 复制方法 
  118.      */ 
  119.     public function copy() { 
  120.         echo $this->_name, ' do copy action.<br />'
  121.     } 
  122.   
  123.     /** 
  124.      * 粘贴方法 
  125.      */ 
  126.     public function paste() { 
  127.         echo $this->_name, ' do paste action.<br />'
  128.     } 
  129.   
  130. /** 
  131.  * 请求者角色 
  132.  */ 
  133. class Invoker { 
  134.   
  135.     private $_command
  136.   
  137.     public function __construct(Command $command) { 
  138.         $this->_command = $command
  139.     } 
  140.   
  141.     public function action() { 
  142.         $this->_command->execute(); 
  143.     } 
  144.   
  145. /** 
  146.  * 客户端 
  147.  */ 
  148. class Client { 
  149.   
  150.      /** 
  151.      * Main program. 
  152.      */ 
  153.     public static function main() { 
  154.         $receiver = new Receiver('phpppan'); 
  155.         $pasteCommand = new PasteCommand($receiver); 
  156.         $copyCommand = new CopyCommand($receiver); 
  157.   
  158.         $macroCommand = new DemoMacroCommand(); 
  159.         $macroCommand->add($copyCommand); 
  160.         $macroCommand->add($pasteCommand); 
  161.   
  162.         $invoker = new Invoker($macroCommand); 
  163.         $invoker->action(); 
  164.   
  165.         $macroCommand->remove($copyCommand); 
  166.         $invoker = new Invoker($macroCommand); 
  167.         $invoker->action(); 
  168.     } 
  169.   
  170. Client::main(); 
  171.   
  172.   
  173. ?> 

作者:pan 原始出处:http://www.phppan.com/2010/08/php-design-pattern-15-comman/