命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
//Receiver类,知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接收者。
class Receiver
{
public:
void Action()
{
printf("执行请求!");
}
};
//Command类,用来声明执行操作的接口。
class Command
{
protected:
Receiver *receiver;
public:
Command(Receiver *receiver)
{
this->receiver = receiver;
}
virtual void Execute() = 0;
};
//具体Command类,将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute
class ConcreteCommand : public Command
{
public:
ConcreteCommand(Receiver *reciver) : Command(reciver){}
public:
void Execute()
{
receiver->Action();
}
};
//Invoker类,要求该命令执行这个请求
class Invoker
{
private:
//list<Command> commands; //可以是一组,见例子
Command *command;
public:
void SetCommand(Command *command)
{
this->command = command;
}
void ExecuteCommand()
{
command->Execute();
}
};
//客户端代码,创建一个具体命令对象并设定它的接收者
int main()
{
Receiver r;
ConcreteCommand cc(&r);
Invoker i;
i.SetCommand(&cc);
i.ExecuteCommand();
return 1;
}
命令模式能用来做什么?
第一:它能较容易的设计一个命令队列;
第二:在需要的情况下,可以比较容易的将命令计入日志。
第三:允许接收请求的一方决定是否要否决请求。
第四:可以容易地实现对请求的撤销和重做;
第五:由于加进新的具体命令类不影响其他的类,因为增加新的具体命令类很容易。
命令模式的关键优点是:把请求一个操作的对象与指导怎么执行一个操作的对象分割开。
敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作功能时,把原来的代码重构为命令模式才有意义。
下面例子体现了命令模式的作用及特点:
#include <iostream>
#include <list>
#include <string>
#include <time.h>
//#include<stdio.h>
using namespace std;
//路边烤肉的例子,服务员是Invoker,烤肉者是Receiver
//烤肉者类
class Barbecuer
{
public:
//烤羊肉
void BakeMutton()
{
cout << "烤羊肉串!" << endl;
}
void BakeChickenWing()
{
cout << "烤鸡翅!" << endl;
}
};
//抽象命令类
//Command类,用来声明执行操作的接口。
class Command
{
public:
string instruction;
protected:
Barbecuer *receiver;
public:
Command(Barbecuer *receiver)
{
this->receiver = receiver;
}
virtual void Execute() = 0;
};
//具体Command类,烤鸡翅命令
class BakeChickenWingCommand : public Command
{
public:
BakeChickenWingCommand(Barbecuer *reciver) : Command(reciver){instruction = "烤鸡翅";}
public:
void Execute()
{
receiver->BakeChickenWing();
}
};
//具体Command类,烤羊肉串命令
class BakeMuttonCommand : public Command
{
public:
BakeMuttonCommand(Barbecuer *reciver) : Command(reciver){instruction = "烤羊肉";}
public:
void Execute()
{
receiver->BakeMutton();
}
};
//服务员类,Invoker类
class Waiter
{
private:
list<Command *> commands;
public:
//添加订单,因为订单不可能只点一样菜,所以是list
void SetOrder(Command *command)
{
if(command->instruction == "烤鸡翅")
{
cout << "服务员:没有鸡翅了,请点别的烧烤。"<<endl;
}
else
{
commands.push_back(command);
time_t t;
time(&t);
cout << "增加了订单:" << command->instruction << " 时间:"<<ctime(&t)<<endl;
}
}
void CancelOrder(Command *command)
{
commands.remove(command);
time_t t;
time(&t);
cout << "取消了了订单:" << command->instruction << " 时间:"<<ctime(&t)<<endl;
}
//通知全部执行
void Notify()
{
list<Command *>::iterator iter = commands.begin();
for(;iter!=commands.end();iter++)
{
(*iter)->Execute();
}
}
};
//客户端
int main()
{
//开店前准备
Barbecuer boy;
BakeMuttonCommand bakeMttonCommand1(&boy);
BakeMuttonCommand bakeMttonCommand2(&boy);
BakeChickenWingCommand bakeChickenWingCommand(&boy);
Waiter girl;
//顾客点餐
girl.SetOrder(&bakeMttonCommand1);
girl.SetOrder(&bakeMttonCommand2);
girl.SetOrder(&bakeChickenWingCommand);
//点菜完毕,通知厨房
girl.Notify();
//取消羊肉1
girl.CancelOrder(&bakeMttonCommand1);
return 1;
}