命令模式即将请求封装为对象Commond。
执行者可以执行多个操作,即执行者才是操作真正的实现者。设其为操作0-9。每个操作都封装了一个对应的Commond类。当该Commond被调用时,Commond会令执行者执行其对应的操作。
用户需要执行者执行某个操作序列。比如这个序列为06131109,共8个操作。那么用户创建8个Commond对象,然后将这8个Commond对象依次交给一个调用者Invoker,该调用者Invoker会依次调用Commond。从而这8个Commond对象会顺次执行。即调用者Invoker负责接收命令并调用命令的执行函数。
实际上,8个Commond对象,其中有重复的Commond。由于Commond仅仅负责请求,而并非具体执行,故同种Commond只用创建一个对象即可。当将Commond提交给调用者Invoker时,提交Commond的指针即可。
因此,每个Commond都可以进行记录。可以对Commond进行重做,也可以进行撤销(撤销需要执行者有对应的撤销函数)。还可以设置一个标志位,当命令序列进行执行时,一旦某个命令的标志位为不执行,那么可以跳过该命令,直接执行下一条命令。
对于一个Commond序列,由于可以记录,所以只要原始输入相同,那么就可以再现整个执行过程。
1. 定义命令基类
命令基类定义了命令的执行接口Execute()。所有命令都继承该标准接口。
class Command
{
public:
virtual void Execute() = 0;
};
2. 定义接收者
接收者负责最终行为的执行,即真正的执行者。
注意执行具体行为并不是由命令负责,而是接收者负责。也就是说,命令只是一种通知手段,告知接收者要做什么。至于怎么做,是接收者负责的。
因此,接收者的Action()函数才是真正的功能实现函数。
考虑到命令有多条,所以可以在同一个Receiver中定义多个Action()函数,以对应每一条命令;或者基于Receiver派生,对于每一条命令,都定义一个对应的Receiver。
class Receiver
{
public:
void Action() {};
};
3. 定义具体命令
具体命令从Command类派生。
每个具体命令都要指定一个接收者,以执行该命令对应的功能。在该命令的Execute()接口函数中,会令接收者执行某个指定的函数。这样就实现了命令对应功能的执行。
class ConcreteCommand : public Command
{
public:
ConcreteCommand(Receiver* pReceiver)
{
this->_recv = pReceiver;
};
virtual void Execute()
{
this->_recv->Action();
};
private:
Receiver* _recv;
};
4. 定义调用者
调用者用于接收命令,并调用命令的执行函数,从而进一步使得命令调用接收者的Action()函数来实现功能。
class Invoker
{
public:
Invoker(Command* pCommand)
{
this->_cmd = pCommand;
};
void Invoke()
{
this->_cmd->Execute();
};
private:
Command* _cmd;
};
5. 用户使用
对于用户而言,需要创建命令,并将命令与其接收者进行绑定。
然后通过调用者Invoker来对命令进行调用,从而间接调用了Receiver的Action()函数。
void main()
{
//创建具体命令对象pCmd,并设定它的接收者pRev
Receiver* pRev = new Receiver();
Command* pCmd = new ConcreteCommand(pRev);
//将命令提交给调用者,并由调用者进行调用
Invoker* pInv = new Invoker(pCmd);
pInv->Invoke();
}
整个过程为:
用户创建命令,并设定其接收者
→用户将命令提交给调用者
→用户调用调用者的Invoke()函数
→调用者的Invoke()函数调用命令的Execute()函数
→命令的Execute()函数调用接收者的Action()函数
→操作得到执行