C++ 设计模式-命令模式
命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,从而可以用不同的请求对客户进行参数化,并且支持请求的排队、记录日志以及撤销操作。命令模式的核心思想是将“请求”封装为一个对象,使得可以用不同的请求、队列或者日志来参数化其他对象。
示例:支持撤销操作的计算器
实现一个简单的计算器,它可以执行加法和减法操作,并且支持撤销上一次操作。
1. 定义命令接口
命令接口包含两个方法:execute
(执行操作)和 unexecute
(撤销操作)。
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
virtual void unexecute() = 0; // 撤销操作
};
2. 创建接收者类
接收者类是实际执行操作的对象。在这里,接收者是一个计算器,它可以执行加法和减法。
class Calculator {
private:
int value = 0; // 当前值
public:
void add(int x) {
value += x;
std::cout << "Added " << x << ", current value: " << value << std::endl;
}
void subtract(int x) {
value -= x;
std::cout << "Subtracted " << x << ", current value: " << value << std::endl;
}
int getValue() const {
return value;
}
};
3. 创建具体命令类
我们为加法和减法分别创建具体的命令类。每个命令类都持有一个接收者对象(计算器)和一个操作数。
// 加法命令
class AddCommand : public Command {
private:
Calculator& calculator;
int operand;
public:
AddCommand(Calculator& calc, int x) : calculator(calc), operand(x) {}
void execute() override {
calculator.add(operand);
}
void unexecute() override {
calculator.subtract(operand); // 撤销加法操作
}
};
// 减法命令
class SubtractCommand : public Command {
private:
Calculator& calculator;
int operand;
public:
SubtractCommand(Calculator& calc, int x) : calculator(calc), operand(x) {}
void execute() override {
calculator.subtract(operand);
}
void unexecute() override {
calculator.add(operand); // 撤销减法操作
}
};
4. 创建调用者类
调用者类(Invoker
)负责执行命令,并且可以支持撤销操作。我们可以通过一个栈来记录执行过的命令,以便撤销。
#include <stack>
#include <memory>
class Invoker {
private:
std::stack<std::shared_ptr<Command>> commandHistory; // 命令历史记录
public:
void executeCommand(std::shared_ptr<Command> command) {
if (command) {
command->execute();
commandHistory.push(command); // 将命令记录到历史中
}
}
void undo() {
if (!commandHistory.empty()) {
auto lastCommand = commandHistory.top();
lastCommand->unexecute(); // 撤销上一次操作
commandHistory.pop(); // 从历史记录中移除
} else {
std::cout << "No commands to undo." << std::endl;
}
}
};
5. 客户端代码
在客户端代码中,我们创建计算器对象、命令对象,并通过调用者执行和撤销操作。
int main() {
Calculator calculator;
Invoker invoker;
// 创建命令
auto addFive = std::make_shared<AddCommand>(calculator, 5);
auto subtractThree = std::make_shared<SubtractCommand>(calculator, 3);
// 执行加法命令
invoker.executeCommand(addFive); // 输出: Added 5, current value: 5
// 执行减法命令
invoker.executeCommand(subtractThree); // 输出: Subtracted 3, current value: 2
// 撤销上一次操作
invoker.undo(); // 输出: Added 3, current value: 5
// 再次撤销
invoker.undo(); // 输出: Subtracted 5, current value: 0
// 尝试撤销空历史
invoker.undo(); // 输出: No commands to undo.
return 0;
}
输出结果
Added 5, current value: 5
Subtracted 3, current value: 2
Added 3, current value: 5
Subtracted 5, current value: 0
No commands to undo.
总结
- 封装请求:将加法和减法操作封装为命令对象。
- 解耦调用者和接收者:调用者(
Invoker
)不需要知道具体的操作细节,只需要调用命令对象的execute
和unexecute
方法。 - 支持撤销操作:通过记录命令历史,可以轻松实现撤销功能。