1、意图
- 将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或记录日志;以及支持可撤销的操作。
2、动机
- 有时必须向某对象提交请求,但并不知道关于被请求的操作(或请求的接受者)的任何信息。
- 提交一个请求的对象仅需要知道如何提交它,而不需知道该请求将会被如何执行。
3、适用性
- COMMAND模式是回调机制的一个面向对象的替代品。
- 在不同的时刻指定、排列和执行请求。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。
- 支持取消操作。COMMAND的Execute操作在执行实际操作前可将状态存储起来,取消操作时这个状态用来消除影响。
- 支持修改日志。用于崩溃恢复。
- 用构建在原语操作上的高层操作构造一个系统。常用于支持事务(transaction)的信息系统。
4、结构
5、参与者
- Command
- 定义执行的操作的接口。 - ConcreteCommand
- 将一个接收者对象绑定于一个命令;
- 调用接收者相应的操作,以实现Execute。 - Client
- 创建一个具体对象并指定其接收者。 - Invoker
- 要求该命令执行这个请求 - Receiver
- 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
6、协作
- Client创建一个ConcreteCommand对象并指定它的receiver对象。
- 某Invoker对象存储该ConcreteCommand对象。
- 该Invoker对象通过调用Command对象的Execute操作来提交一个请求。若该命令是可撤销的,ConcreteCommand就在执行Execute操作之前存储当前状态以用于取消该命令。
- ConcreteCommand对象调用它的Receiver对象以实现该请求。
7、效果
- 将调用操作的对象与知道如何实现该操作的对象解耦;
- Command是头等的对象,它们可像其他对象那样被操纵和扩展;
- 可将多个命令组合成一个复合命令。
- 增加新的Command很容易,无需改变已有的类。
8、实现
- 命令对象的能力 可大可小,一个极端是它仅确定一个接收者和执行该请求的动作,另一个极端是它自己实现所有功能,根本不需要额外的接收者对象。
- 支持撤销(Undo)和重做(Redo) ConcreteCommand可能需要存储额外的状态信息,包括:
1)接收者对象,它真正执行处理 该请求的各操作;
2)接收者执行操作的参数;
3)如果处理请求的操作会改变接收者对象中的某些值,那么这些值也必须先存储起来。接收者还必须提供一些操作,以使该命令可将接收者恢复到它先前的状态。
历史调用列表中,如果命令的状态在各次调用之间会发生变化,那么就必须在放入历史列表前先拷贝下来以区分相同命令的不同调用。 - 避免取消操作过程中的错误积累 在实现一个可靠的、能保持原先语义的取消/重做机制时,可能会遇到滞后影响问题。由于命令的重复执行可能会积累错误,以至一个应用的状态最终偏离初始值。这就有必要在Command中存入更多的信息以保证对象可被精确的复原成它们的初始状态。可使用Memento模式来让该Command访问这些信息而不暴露对象的其他内部信息。
- 使用C++模板 对(1)不能撤销 (2)不需要参数的命令,可使用C++模板实现,不需要为每一种动作和接收者都创建一个Command子类。
9、相关模式
- Composite模式可被用来实现复合命令;
- Memento模式可用来保持某个状态,Command用这个状态来取消它执行的效果;
- 在放入历史列表中之前必须被拷贝的那些Command起到原型(Prototype模式)的作用。