命令模式(Command Pattern)详解
命令模式是一种行为设计模式,它将请求或操作封装为对象,从而使你可以参数化客户端对象,对请求排队或记录请求日志,以及支持可撤销的操作。
核心概念
- 命令(Command):声明执行操作的接口
- 具体命令(Concrete Command):将接收者对象与动作绑定
- 接收者(Receiver):知道如何执行与请求相关的操作
- 调用者(Invoker):要求命令对象执行请求
- 客户端(Client):创建具体命令对象并设置其接收者
模式结构
Invoker
|__ command: Command
|__ executeCommand()
Command (Interface/Abstract Class)
|__ execute()
|__ undo()
ConcreteCommand
|__ execute()
|__ undo()
|__ receiver: Receiver
Receiver
|__ action()
实现示例(C++)
#include <iostream>
#include <vector>
#include <memory>
// 接收者类 - 电灯
class Light {
public:
void on() {
std::cout << "电灯打开了" << std::endl;
}
void off() {
std::cout << "电灯关闭了" << std::endl;
}
};
// 命令接口
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
virtual void undo() = 0;
};
// 具体命令 - 开灯命令
class LightOnCommand : public Command {
public:
explicit LightOnCommand(Light* light) : light_(light) {}
void execute() override {
light_->on();
}
void undo() override {
light_->off();
}
private:
Light* light_;
};
// 具体命令 - 关灯命令
class LightOffCommand : public Command {
public:
explicit LightOffCommand(Light* light) : light_(light) {}
void execute() override {
light_->off();
}
void undo() override {
light_->on();
}
private:
Light* light_;
};
// 调用者 - 遥控器
class RemoteControl {
public:
void setCommand(std::shared_ptr<Command> command) {
command_ = command;
}
void pressButton() {
command_->execute();
commandHistory_.push_back(command_);
}
void pressUndo() {
if (!commandHistory_.empty()) {
commandHistory_.back()->undo();
commandHistory_.pop_back();
}
}
private:
std::shared_ptr<Command> command_;
std::vector<std::shared_ptr<Command>> commandHistory_;
};
// 客户端代码
int main() {
// 创建接收者
Light livingRoomLight;
// 创建具体命令
auto lightOn = std::make_shared<LightOnCommand>(&livingRoomLight);
auto lightOff = std::make_shared<LightOffCommand>(&livingRoomLight);
// 创建调用者
RemoteControl remote;
// 测试开灯
remote.setCommand(lightOn);
remote.pressButton(); // 开灯
// 测试关灯
remote.setCommand(lightOff);
remote.pressButton(); // 关灯
// 测试撤销
remote.pressUndo(); // 撤销关灯(即开灯)
remote.pressUndo(); // 撤销开灯(即关灯)
return 0;
}
命令模式优点
- 解耦:分离调用操作的对象和知道如何执行操作的对象
- 可扩展:可以轻松添加新命令而不改变现有代码
- 支持撤销/重做:可以实现命令的撤销和重做功能
- 支持事务:可以将一组命令组合成一个复合命令
- 支持队列和日志:可以实现命令的排队执行和日志记录
适用场景
- 需要将操作表示为对象时
- 需要支持撤销/重做操作时
- 需要支持事务或命令排队时
- 需要实现回调机制时
- 需要记录操作历史时
现实生活例子:餐厅点餐系统
// 接收者 - 厨师
class Chef {
public:
void cookPasta() {
std::cout << "厨师正在做意大利面" << std::endl;
}
void cookSteak() {
std::cout << "厨师正在做牛排" << std::endl;
}
};
// 具体命令 - 做意大利面命令
class CookPastaCommand : public Command {
public:
explicit CookPastaCommand(Chef* chef) : chef_(chef) {}
void execute() override {
chef_->cookPasta();
}
void undo() override {
std::cout << "撤销意大利面订单" << std::endl;
}
private:
Chef* chef_;
};
// 具体命令 - 做牛排命令
class CookSteakCommand : public Command {
public:
explicit CookSteakCommand(Chef* chef) : chef_(chef) {}
void execute() override {
chef_->cookSteak();
}
void undo() override {
std::cout << "撤销牛排订单" << std::endl;
}
private:
Chef* chef_;
};
// 调用者 - 服务员
class Waiter {
public:
void takeOrder(std::shared_ptr<Command> order) {
orders_.push_back(order);
}
void submitOrders() {
for (auto& order : orders_) {
order->execute();
}
orders_.clear();
}
private:
std::vector<std::shared_ptr<Command>> orders_;
};
// 使用示例
int main() {
Chef chef;
Waiter waiter;
auto pastaOrder = std::make_shared<CookPastaCommand>(&chef);
auto steakOrder = std::make_shared<CookSteakCommand>(&chef);
waiter.takeOrder(pastaOrder);
waiter.takeOrder(steakOrder);
waiter.submitOrders(); // 厨师开始烹饪
return 0;
}
命令模式通过将请求封装为对象,提供了更大的灵活性和控制能力,使得请求的发送者和接收者解耦,同时支持撤销、事务等高级功能。