1 含义
命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
2 UML类图
参与者:
Command:声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
ConcreteCommand: 具体执行的命令,将接收者对象的动作绑定其中。
Invoker:命令的调用者即请求的发送者,要求该命令执行请求。
Receiver:命令接受者,执行命令的对象,知道如何实施与执行一个请求相关的操作。
3 代码实现
举例:日常生活中,我们经常到饭店去吃饭,当然我们要吃什么会给服务员说,服务员在转告给厨师,点菜可以看做一个请求,看它如何用命令模式实现。
#include<iostream>
#include<string>
using namespace std;
//命令的处理者:厨师
class Chef
{
public:
void cook(string name)
{
cout << "厨师做一道" << name << endl;
}
};
//命令抽象类:点菜
class Command
{
protected:
Chef* chef_;
public:
Command(Chef* chef) :chef_(chef) {}
virtual void excute() = 0;
};
命令具体类:牛肉
class BeefCmd :public Command
{
public:
BeefCmd(Chef *chef) :Command(chef) {}
virtual void excute() override
{
chef_->cook("青椒炒牛肉");
}
};
//命令具体类:土豆
class PotatoCmd :public Command
{
public:
PotatoCmd(Chef *_chef) :Command(_chef) {}
virtual void excute()
{
chef_->cook("青椒炒土豆丝");
}
};
//命令接受者:服务员
class Waiter
{
private:
Command* cmd_;
public:
void ReciveCmd(Command* cmd)
{
cmd_ = cmd;
}
void DealCmd()
{
cmd_->excute();
}
};
//饭店场景
int main()
{
//服务员
Waiter *waiter = new Waiter;
//厨师
Chef *chef = new Chef;
//客人开始点菜
Command *beef = new BeefCmd(chef);
Command *potato = new PotatoCmd(chef);
//下单
waiter->ReciveCmd(beef);
waiter->DealCmd();
waiter->ReciveCmd(potato);
waiter->DealCmd();
return 0;
}
4 优缺点
4.1 优点
将调用操作的对象和实现操作的对象进行了解耦。
具体命令扩展方便。
4.2 缺点
有几个具体命令就有多少具体类,可能需要大量具体命令类。
5 适用场景
系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
系统需要在不同的时间指定请求、将请求排队和执行请求。
系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
系统需要将一组操作组合在一起,即支持宏命令
参考
1.https://blog.csdn.net/a369189453/article/details/81320249
2.https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html
3.https://refactoringguru.cn/design-patterns/command