实例
例如来一家饭馆吃饭,点两个菜
class Cook {
public:
//做红烧鱼
void cook_fish() {
cout << "做一盘红烧鱼" << endl;
}
//做锅包肉
void cook_meat() {
cout << "做一盘锅包肉" << endl;
}
};
主函数中让厨师做菜:
Cook* pcook = new Cook();
pcook-> cook_finsh();
pcook-> cook_meat();
如果顾客较多,每个人都去找厨师,那么很容易出错,因此写上标签,报给厨师
//服务员
class Command {
public:
Command(Cook* pcook) {
m_pcook = pcook;
}
virtual ~Command() {}
virtual void Execute() = 0;
protected:
Cook* m_pcook; //子类需要访问
};//下命令
class CommandFish :public Command {
public:
CommandFish(Cook* pcook) :Command(pcook) {}
virtual void Execute() {
m_pcook->cook_fish();
}
};class CommandMeat :public Command {
public:
CommandMeat(Cook* pcook) :Command(pcook) {}
virtual void Execute() {
m_pcook->cook_meat();
}
};
主函数中点单:
Cook cook;
Command* pcmd1 = new CommandFish(&cook);pcmd1-> Execute();
Command* pcmd2 = new CommandMeat(&cook);
pcmd2-> Execute();
delete pcmd1;
delete pcmd2;
但是实际上没必要每个菜品都写一个便签,可以在一张纸上写不同的菜,引入服务员
#include <list>
class Waiter {
public:
void AddCommand(Command* pcommand) {
m_cmmlist.push_back(pcommand);
}
void DeleteCommand(Command* pcommand) {
m_cmmlist.remove(pcommand);
}
void SetCommand(Command* pcommand) {
m_pcommand = pcommand;
}
void Notify() {
for (auto iter = m_cmmlist.begin(); iter != m_cmmlist.end(); ++iter) {
(*iter)->Execute();
}
}
private:
Command* m_pcommand; //服务员拿着菜品便签
std::list<Command*> m_cmmlist;
};
Cook cook;
Command* pcmd1 = new CommandFish(&cook);
Command* pcmd2 = new CommandMeat(&cook);Waiter* pwaiter = new Waiter();
pwaiter->AddCommand(pcmd1);
pwaiter->AddCommand(pcmd2);pwaiter->Notify();
delete pcmd1;
delete pcmd2;
delete pwaiter;
UML图
命令模式的UML类图中包含5种角色
(1)Receiver接收者类:知道如何实施与执行一个请求的相关操作,这里的Cook类
(2)Invoker调用者类:请求的发送者,通过命令对象执行请求,这里的Waiter类
(3)Command抽象命令类:声明执行的接口,这里的Command类
(4)ConcreteCommand具体命名类:抽象命令的子类,这里的CommandFish和CommandMeat
(5)Client客户端:创建具体命令类,并设定它的接收者,这里是main函数中的几行代码
定义
将一个请求或者命令(做红烧鱼和锅包肉)封装为一个对象,以便这些请求可以以对象的方式通过参数进行传参(参数化),对象化之后的请求还可以排队执行或者根据需求进行使用。
命令模式的核心实现手段,是将成员函数的调用封装成命令对象,也就是对请求进行封装,命令对象将动作和接收者包裹到对象中,并且只暴露出了一个Execute方法以让接受者执行动作。
命令模式用途研究
前面的范例中,构造Command对象是往往要传递一个事先构造好的Cook对象,考虑到Command对象的独立性,调整一下代码,之后就可以直接使用new来构造
virtual ~Command(){
if (m_pcook != nullptr){
delete m_pcook;
m_pcook = nullptr;
}
}
命令模式适合使用的场景:
(1)在绘图软件中
(2)遥控器实现对控制设备的解耦
(3)任务的定期调度执行
(4)游戏中时光倒流系统和回放系统的实现