让我们用一个简单易懂的日常生活例子来解释命令模式(Command Pattern)。假设有一个智能家居系统,可以通过语音助手来控制各类家电,如电视、灯和音响。这些家电可以接受不同的命令,比如打开、关闭、调节音量或亮度等。命令模式可以帮助我们更好地实现这一系统。
生活中的实际应用:智能家居系统
假设你有一个智能家居系统,可以通过语音助手来控制家中的设备。每个家电都可以接受特定的命令,如打开、关闭、调节等。为了让系统更易于维护和扩展,我们可以使用命令模式。
主要角色
- 客户(Client):创建具体命令对象并设置其接收者。
- 命令接口(Command):定义一个执行操作的接口。
- 具体命令(ConcreteCommand):实现命令接口,执行具体的操作。
- 调用者(Invoker):持有命令对象并在某个时间点执行命令。
- 接收者(Receiver):真正执行命令的对象。
编码示例
下面的代码使用命令模式来实现智能家居中的设备控制。
#include <iostream>
#include <vector>
// 命令接口
class Command {
public:
virtual ~Command() {}
virtual void execute() = 0;
virtual void undo() = 0;
};
// 具体命令:打开电视
class TV {
public:
void on() {
std::cout << "电视打开了" << std::endl;
}
void off() {
std::cout << "电视关闭了" << std::endl;
}
};
class TVOnCommand : public Command {
private:
TV* tv;
public:
TVOnCommand(TV* t) : tv(t) {}
void execute() override {
tv->on();
}
void undo() override {
tv->off();
}
};
// 具体命令:打开灯
class Light {
public:
void on() {
std::cout << "灯打开了" << std::endl;
}
void off() {
std::cout << "灯关闭了" << std::endl;
}
};
class LightOnCommand : public Command {
private:
Light* light;
public:
LightOnCommand(Light* l) : light(l) {}
void execute() override {
light->on();
}
void undo() override {
light->off();
}
};
// 调用者:遥控器
class RemoteControl {
private:
Command* command;
std::vector<Command*> history;
public:
void setCommand(Command* cmd) {
command = cmd;
}
void pressButton() {
if (command) {
command->execute();
history.push_back(command);
}
}
void pressUndo() {
if (!history.empty()) {
Command* cmd = history.back();
history.pop_back();
cmd->undo();
}
}
};
// 主函数
int main() {
// 创建接收者
TV* tv = new TV();
Light* light = new Light();
// 创建具体命令
Command* tvOnCommand = new TVOnCommand(tv);
Command* lightOnCommand = new LightOnCommand(light);
// 创建调用者
RemoteControl* remote = new RemoteControl();
// 设置并执行命令
remote->setCommand(tvOnCommand);
remote->pressButton();
remote->setCommand(lightOnCommand);
remote->pressButton();
// 撤销操作
remote->pressUndo();
remote->pressUndo();
// 释放资源
delete tvOnCommand;
delete lightOnCommand;
delete tv;
delete light;
delete remote;
return 0;
}
代码解释
- 命令接口 (
Command
):定义了两个方法execute()
和undo()
,用于执行和撤销操作。 - 具体命令 (
TVOnCommand
和LightOnCommand
):每个具体命令都持有一个接收者对象(如TV
或Light
),并在execute()
和undo()
方法中调用接收者的具体操作。 - 接收者 (
TV
和Light
):实现具体的操作,如打开和关闭设备。 - 调用者 (
RemoteControl
):持有命令对象,调用execute()
方法执行操作,并记录每次执行的命令以支持撤销操作(undo()
)。
总结
命令模式将请求封装为对象,从而使你可以用不同的请求对客户进行参数化。通过这个示例,我们可以看到命令模式的优点:
- 解耦调用者和接收者:调用者(RemoteControl)不需要知道如何执行命令,只需要调用命令对象的
execute()
方法。 - 可扩展性:添加新命令非常容易,只需继承命令接口并实现
execute()
和undo()
方法。 - 支持撤销操作:通过记录执行过的命令,可以轻松实现操作的撤销。