意图:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及
支持可撤消的操作。
很迷惑,看了之后不知道在说什么。如果这样说,我想理解的更清楚些 。本模式把“发出命令的责任和执行命令的责任分割开,委派给不同的对象”。或者我们也可以这样理解: “请求”即 方法,命令 如“打球” 这就是一个方法,一个请求。我们可以把这个方法提到类的层次,封装为一个对象。当然了有了对象我们就可以把他们排队 可以 对客户进行参数化。关于“参数化” 这点也很难理解, 在C语言里我们经常使用回调函数。回调的基本思想就是用系统提供一些接口函数,将某个其他函数的地址作为其参数之一,可以通过该地址对这个函数进行调用,而被调用的函数就是我们通常所说的回调函数了。在Command模式中做为参数的函数地址就可以用Command对象来替代。即方法提到了类的层次 ,呵呵 又说了一遍。
为什么使用?
1:发出命令以及决定命令何时执行与 命令到底是由谁来执行,怎么执行 显然是两个不同的逻辑。如果把他们放在
一起显然是不合适的,易导致职责不单一,逻辑不清晰。所以需要委派给不同的对象,使他们松耦合。
2:本模式通过引入一个command 中间层,解耦了发出命令和执行命令的逻辑,正因为有了这个中间层我们才可以
在调用者角色中做很多事情,比如延迟命令的执行、为执行的命令记录日志、撤销命令的执行等等。
命令模式涉及到的角色:
- 客户(Client)角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者。
- 命令(Command)角色:声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。
- 具体命令(ConcreteCommand)角色:定义一个接受者和行为之间的弱耦合;实现Execute()方法,负责调用接收考的相应操作。Execute()方法通常叫做执方法。
- 请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。
- 接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。
总结:
1:在应用的过程中可以省略一些不重要的角色。比如,如果只有一个执行者或者执行的逻辑非常简单的话,可以
把执行的逻辑合并到具体命令角色中;如果我们并不需要使用调用者来做额外的功能,仅仅是希望通过命令模式
来解除客户端和接受者之间耦合的话可以省略调用者角色。
2:命令角色的逻辑可以很复杂也可以很简单。这是两个极端。
3:我们可以对命令利用组合模式进行组合。
4:如果不需要对命令做额外操作,比如撤消等功能。那么这个时候命令类也就退化为一个执行者。
5:命令角色除了封装一些不应该放在执行者角色的逻辑(如命令对象可以把状态存储起来,等到客户端需要撤销命
令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供
客户端在需要时,再重新实施命令效果。这些方法/逻辑是不应该放在执行者角色的)外,还提供一个一致简化的
接口方便调用,因为具体执行者的方法接口可能是多种多样的。
6:“何时执行及是否执行”这个逻辑确实如 吕振宇所说,应该放在请求者(Invoker)角色里面,这点阎宏的太白金星
宣悟空上天那个例子容易误导。
7:实际中这个模式应用的很灵活,因此并不应该死套该模式,我们的目标是优雅的设计(灵活 逻辑清晰 消除重复)
因此对于具体问题具体应用该模式 该简化的部分就简化 否则有过度设计,死搬硬套之臭味,对于该臭味我们可
以应用面向对象的设计原则来诊断。注意是诊断而不应将它做为可以任意喷洒的香水。
8:本模式的好处就是把方法提高类的好处,虽然有人抨击说 这不是OO 这是贫血的类。如果我们顽固的这样认为
未免太教条了吧。
实际中的应用:
同样在ACE中,也充分应用了本模式,它在实现主动对象模式时,用到方法对象(方法提到类的层次 还记的吗?)它继承于ACE_Method_Object 类。我们说过 “何时执行”这个逻辑是放在请求者(Invoker)角色里面的,在ACE里 所有的方法对象都被客户(client角色)实例化 并放在启用队列(activation queue)中,ACE_Task类对将该方法对象从队列取出,并调用它的call()方法。 呵呵 ACE_Task类是不是相当于请求者(Invoker)角色 它决定了“何时执行”。由于ACE_Method_Object 类是个接口类,因此 你可以 自己实现 call()方法。 这里是不是很灵活的应用了command 模式? 你可以把 ACE_Method_Object 类当作command 角色 或者 执行者角色 看你怎么认为了 !
部分代码如下:
typedef ACE_Method_Request ACE_Method_Object;
》》 这一句你看到了吗?
class ACE_Export ACE_Method_Request
{
public:
/// Constructor.
ACE_Method_Request (unsigned long priority = 0);
/// Destructor.
virtual ~ACE_Method_Request (void);
// = Accessors.
/// Get priority.
unsigned long priority (void) const;
/// Set priority.
/**
* Priority values are user-defined. The default (set in the constructor)
* is 0. The priority value is used in the ACE_Activation_Queue::enqueue()
* method to order the method requests in the queue by priority.
* 0 is the lowest priority.
*
* @param prio unsigned long, the new priority value for this object.
*
* @sa ACE_Activation_Queue::enqueue
*/
void priority (unsigned long prio);
// = Invocation method (must be overridden by subclasses).
/// Invoked by the scheduler to execute the request.
/**
* This method must be implemented by the subclass to perform the
* desired actions.
*
* @return int; not interpreted by ACE. The scheduler class must
* decide the meaning of this return value and act on it
* if needed.
*/
virtual int call (void) = 0;
private:
/// Disallow copying and assignment.
ACE_Method_Request (const ACE_Method_Request &);
void operator= (const ACE_Method_Request &);
protected:
/// The priority of the request.
unsigned long priority_;
};