1. 作用
命令模式,一个与命令有关的模式。将命令的执行者封装在命令中,命令调用者和接受者(执行者)进行了解耦。
意图:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
2. UML类图
参与者:
- Command:声明执行操作的接口,核心为Execute接口。同时将一个接受者对象绑定于一个动作。
- ConcreteCommand: 调用接受者相应的操作,以实现Execute。
- Invoker:命令的调用者,要求该命令执行请求。
- Receiver:知道如何实施与执行一个请求相关的操作。
3. 实现
举例:日常生活中,我们经常到饭店去吃饭,当然我们要吃什么会给服务员说,服务员在转告给厨师,点菜可以看做一个请求,看它如何用命令模式实现。
代码:
#include <iostream>
#include <string>
using namespace std;
//命令处理者:厨师
class Chef
{
public:
void cook(string name)
{
cout << "厨师做一道" << name <<endl;
}
};
//命令抽象类:点菜
class Command
{
public:
Command(Chef *_chef) :m_pChef(_chef){}
virtual void excute() = 0;
protected:
Chef *m_pChef;
};
//命令具体类:牛肉
class BeefCmd :public Command
{
public:
BeefCmd(Chef *_chef) :Command(_chef){}
virtual void excute()
{
m_pChef->cook("青椒炒牛肉");
}
};
//命令具体类:土豆
class PotatoCmd :public Command
{
public:
PotatoCmd(Chef *_chef) :Command(_chef){}
virtual void excute()
{
m_pChef->cook("青椒炒土豆丝");
}
};
//命令具体类:牛肉
class EggSoupCmd : public Command
{
public:
EggSoupCmd(Chef *_chef) :Command(_chef){}
virtual void excute()
{
m_pChef->cook("西红柿蛋汤");
}
};
//命令接受者:服务员
class Waiter
{
public:
void ReciveCmd(Command *cmd)
{
m_Cmd = cmd;
}
void dealCmd()
{
m_Cmd->excute();
}
private:
Command *m_Cmd;
};
//饭店场景
int main()
{
//服务员
Waiter *waiter = new Waiter;
//厨师
Chef *chef = new Chef;
//客人开始点菜
Command *beef = new BeefCmd(chef);
Command *potato = new PotatoCmd(chef);
Command *eggSoup = new EggSoupCmd(chef);
//下单
waiter->ReciveCmd(beef);
waiter->dealCmd();
waiter->ReciveCmd(potato);
waiter->dealCmd();
waiter->ReciveCmd(eggSoup);
waiter->dealCmd();
return 0;
}
结果:
厨师做一道青椒炒牛肉
厨师做一道青椒炒土豆丝
厨师做一道西红柿蛋汤
请按任意键继续. . .
4. 优缺点
优点:
- 将调用操作的对象和实现操作的对象进行了解耦。
- 具体命令扩展方便。
缺点:
- 有几个具体命令就有多少具体类。
5. 适用场景
只要是你认为可以看做命令的地方都可以使用命令模式。
6. 总结
命令模式在实际软件设计中经常使用,想想接收者如果是队列,开一个线程从队列中取出命令来执行。这种用法比比皆是。