本文章属于专栏- 概述 - 《设计模式(极简c++版)》-CSDN博客
模式说明
- 方案: 命令模式将请求封装成一个对象,从而允许客户端参数化对象,将请求排入队列或者记录请求日志,以及支持可撤销的操作。
- 优点:
- 解耦了发送者和接收者,发送者无需知道接收者的细节,只需知道命令即可。
- 支持撤销操作,因为命令对象包含了执行操作所需的信息。
- 缺点:
- 可能会导致类的数量增加,因为每个命令都需要一个具体的命令类。
本质思想:把调用的语义封装在一个具体的命令对象中,再创建一个执行调用命令的方法,这样对于所有传入的命令,都可以复用"调用命令的方法"。比如"一只鸟飞起来,然后吃东西",会有一个有一个调用命令的方法,做的事情是"先执行A,再执行B",然后传入命令A为"燕子飞起来",传入"燕子吃东西"。核心收益是,命令调用者的逻辑就可以复用了。
实践建议:在命令调用顺序固定,且使用高频时,把这部分逻辑抽象出命令模式。降低命令流程和命令本身的耦合。注意这块不适合放在业务占用cpu极高的代码部分,它对性能有少量影响。
代码示例:
cpp
#include <iostream>
#include <vector>
// Command Interface
class Command {
public:
virtual void execute() = 0;
};
// Receiver
class Bird {
public:
virtual void fly() = 0;
virtual void eat() = 0;
};
// Concrete Receiver
class Sparrow : public Bird {
public:
void fly() override {
std::cout << "Sparrow is flying." << std::endl;
}
void eat() override {
std::cout << "Sparrow is eating." << std::endl;
}
};
// Concrete Command for flying
class FlyCommand : public Command {
private:
Bird* bird;
public:
FlyCommand(Bird* bird) : bird(bird) {}
void execute() override {
bird->fly();
}
};
// Concrete Command for eating
class EatCommand : public Command {
private:
Bird* bird;
public:
EatCommand(Bird* bird) : bird(bird) {}
void execute() override {
bird->eat();
}
};
// Invoker
class Invoker {
private:
std::vector<Command*> commands;
public:
void addCommand(Command* command) {
commands.push_back(command);
}
void executeCommands() {
for (Command* command : commands) {
command->execute();
}
}
};
int main() {
Sparrow sparrow;
FlyCommand flyCommand(&sparrow);
EatCommand eatCommand(&sparrow);
Invoker invoker;
invoker.addCommand(&flyCommand);
invoker.addCommand(&eatCommand);
invoker.executeCommands();
return 0;
}
/*
Output:
Sparrow is flying.
Sparrow is eating.
*/