什么是命令模式?
- 将请求转换为一个包含与请求相关的所有信息的独立对象。从而使你可以用不同的请求方法进行参数化,并且能够对请求进行排队、记录请求日志以及撤销请求操作。
- 命令模式属于行为设计模式
如何理解命令模式
命令模式很像我们订外卖(淘宝),用户下单,订单中包裹了商户的信息及订餐数量,外卖平台作为接收者将订单再通知到商户,商户执行操作。
命令模式的步骤
源自ChatGpt的总结
- 定义一个 Command 抽象类,它声明了一个抽象的 execute() 方法,该方法用于执行命令。
- 创建一个实现了 Command 抽象类的实体类,该类实现了 execute() 方法,用于执行具体的命令。
- 创建一个 Invoker 类,该类持有 Command 类的一个实例,并调用实例的 execute() 方法来实现命令的调用。
- 创建客户端,在客户端中创建一个具体的 Command 对象,并设置它的接收者。
- 创建 Invoker 对象,并将创建的 Command 对象设置到 Invoker 对象中。
- 调用 Invoker 对象的 execute() 方法来执行命令。
代码描述
我们这里用户头像为例子
- 首先需要接口类
/*通用命令*/
class Command {
public:virtual ~Command() {}virtual void Execute() const = 0;
};
/*通用处理人*/
class Receiver {
public:virtual void DoFuncA(const int a) = 0;virtual void DoFuncB(const int b) = 0;
};
- 创建具体命令
/*实例化一个厨师类的处理人*/
class CookReceiver : public Receiver {
public:explicit CookReceiver(const std::string& cook_name) : cook_name_(cook_name) {}void DoFuncA(const int a) { std::cout << "->cook " << cook_name_ << " Receiver: Working sum= " << a << std::endl; }void DoFuncB(const int b){std::cout << "->cook " << cook_name_ << " Receiver: Working food weight=" << b << std::endl;}private:std::string cook_name_;
};
/*实例化一条简单命令*/
class MilkCommand : public Command {
private:int sum_;public:explicit MilkCommand(int sum) : sum_(sum) {}void Execute() const override { std::cout << "->The customer need milk= " << this->sum_ << std::endl; }
};
/*实例化一条复杂的命令*/
class SteakCommand : public Command {public:explicit SteakCommand(std::shared_ptr<Receiver> receiver_cook, int sum, int weight): sum_(sum), weight_(weight), receiver_cook_(receiver_cook){}void Execute() const override{std::cout << "->The customer ordered a steak" << std::endl;this->receiver_cook_->DoFuncA(this->sum_);this->receiver_cook_->DoFuncB(this->weight_);}private:std::shared_ptr<Receiver> receiver_cook_;int sum_ = 0;int weight_ = 0;
};
- 通过中心来分配执行命令
/*饭店前台*/
class Invoker {
private:vector<std::shared_ptr<Command>> command_list_;public:~Invoker() { command_list_.clear(); }void InsertFontCommand(std::shared_ptr<Command> command) { command_list_.insert(command_list_.begin(), command); }void PushBackCommand(std::shared_ptr<Command> command) { command_list_.push_back(command); }void ExecuteCommand(){std::cout << "The customer order start execute!" << std::endl;for (auto& item_command : command_list_) {item_command->Execute();}std::cout << "The customer order finished!" << std::endl;}
};
- 创建用户命令并执行
int main()
{//饭店前台auto invoker = std::make_shared<Invoker>();//创建厨师小明auto receiver_cook_user = std::make_shared<CookReceiver>("xiao ming");//订购牛排并指定小明厨师制作invoker->PushBackCommand(make_shared<SteakCommand>(receiver_cook_user, 5, 100));//订购牛奶invoker->InsertFontCommand(make_shared<MilkCommand>(5));//执行订单invoker->ExecuteCommand();return 0;
}
- 输出结果如下
命令模式的思考
优点:
- 单一职责,实现了触发和执行的解耦操作;
- 复合开闭原则,无需修改原有代码,就可增加新的命令
- 可以把多个操作组合成一个复杂的命令,从而实现复杂的逻辑
- 排队中的操作命令可以排序或撤销
- 维护日志方便,更好的回溯操作
缺点:
- 简单的逻辑套用命令模式,由于中间传递调用者的加入会变得复杂
- 如果命令过多,很容易出现类数量膨胀的情况
总结:
- 如果遇到复杂的问题,尤其是客户端这种,命令模式是一种很好的解耦UI和逻辑的设计方式
命令模式与其他模式的比较
- 命令在发送者和请求者之间建立单向连接