【c++设计模式17】行为模式2:命令模式(Command Pattern)
- 一、定义
- 二、适用场景
- 三、过程
- 四、命令模式类图
- 五、C++示例代码
- 六、使用注意事项
原创作者:郑同学的笔记
原创地址:https://zhengjunxue.blog.csdn.net/article/details/132589679
qq技术交流群:921273910
类型 | 序号 | 设计模式 | 描述 |
行为模式 | 1 | 责任链模式 (Chain of Responsibility) | 将这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存下一个处理者。 |
2 | 命令模式 (Command Pattern) | 它将请求封装为一个对象,从而使得可以用不同的请求对客户端进行参数化或将请求放入队列中 | |
3 | 迭代器模式 (Iterator Pattern) | 它提供了一种顺序访问聚合对象中各个元素的方法,而不暴露其内部表示。 | |
4 | 中介者模式 (Mediator Pattern) | 通过中介对象进行通信,从而降低了对象之间的耦合性。 | |
5 | 备忘录模式 (Memento Pattern) | 当需要保存和恢复对象的状态时,可以使用备忘录模式。 | |
6 | 观察者模式 (Observer Pattern) | 当一个对象的状态发生改变时,所有依赖它的对象都会自动收到通知并更新。 | |
7 | 策略模式 (Strategy Pattern) | 定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。客户端代码在运行时选择所需的算法。 | |
8 | 状态模式 (State Pattern | 是在一个类的内部会有多种状态的变化,因为状态变化从而导致其行为的改变,在类的外部看上去这个类就像是自身发生了改变一样。 | |
9 | 模板方法模式 (Template Method Pattern) | 定义了算法的基本骨架,而具体方法则由子类提供具体实现。 | |
10 | 访问者模式 (Visitor Pattern) | 访问者定义了针对不同元素的操作方法,而元素则是被访问者访问的对象。 |
命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而使不同的请求能够以参数化的方式进行参数化,并且能够对请求进行排队或记录日志,以及支持可撤销的操作。
一、定义
命令模式定义了一个抽象命令(Command)接口和具体命令(Concrete Command)类,每个具体命令类都实现了抽象命令接口。命令对象包含了执行操作的方法,将请求的发送者(Invoker)和接收者(Receiver)解耦,使得请求的发送者不需要知道请求的处理细节。请求的发送者只需要通过调用命令对象的执行方法来触发请求的处理。
二、适用场景
命令模式适用于以下情况:
- 当需要将请求发送者和接收者解耦时,采用命令模式可以实现对象之间的松耦合。
- 当需要对请求进行参数化时,可以使用命令模式将请求封装为一个对象,并将特定的请求参数传递给该对象。
- 当需要支持撤销操作时,可以使用命令模式来保存请求的历史记录,方便撤销和重做操作。
- 当需要将一些操作封装成一系列的高级操作时,可以使用命令模式来组合这些操作。
三、过程
命令模式的过程包括以下几个角色:
- 命令接口(Command Interface):定义命令的统一接口,声明执行命令的方法。
- 具体命令(Concrete Command):实现命令接口,封装了具体的请求操作和接收者。
- 命令发送者(Command Sender):负责创建具体命令对象,并将其发送给命令接收者执行。
- 命令接收者(Command Receiver):执行具体命令所定义的操作。
四、命令模式类图
- 请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
- Command 模式的最终目的就是将一个请求封装成一个对象,
- 这些命令的接收者是电视class TVReceiver,命令被分离出来实现了和电视类的解耦合。通过这种方式可以控制命令执行的时机,
五、C++示例代码
以下是一个使用命令模式的示例代码,在这个示例中,我们将以电视遥控器控制功能为例,展示如何使用命令模式来实现:
#include <iostream>
// 命令接收者:电视
class TVReceiver {
public:
void turnOn() {
std::cout << "电视已打开" << std::endl;
}
void turnOff() {
std::cout << "电视已关闭" << std::endl;
}
};
// 命令接口:电视命令
class TVCommand {
protected:
TVReceiver* receiver;
public:
virtual void execute() = 0;
};
// 具体命令:打开电视
class TurnOnTVCommand : public TVCommand {
public:
explicit TurnOnTVCommand(TVReceiver* receiver) {}
void execute() override {
receiver->turnOn();
}
};
// 具体命令:关闭电视
class TurnOffTVCommand : public TVCommand {
/*private:
TVReceiver* receiver*/;
public:
explicit TurnOffTVCommand(TVReceiver* receiver) {}
void execute() override {
receiver->turnOff();
}
};
// 命令发送者:遥控器
class RemoteController {
private:
TVCommand* command;
public:
void setCommand(TVCommand* command) {
this->command = command;
}
void pressButton() {
std::cout << "按下按钮,执行命令:" << std::endl;
command->execute();
}
};
int main() {
TVReceiver* tv = new TVReceiver();
TurnOnTVCommand* turnOnCommand = new TurnOnTVCommand(tv);
TurnOffTVCommand* turnOffCommand = new TurnOffTVCommand(tv);
RemoteController* remote = new RemoteController();
// 设置具体命令
remote->setCommand(turnOnCommand);
remote->pressButton(); // 打开电视
remote->setCommand(turnOffCommand);
remote->pressButton(); // 关闭电视
delete tv;
delete turnOnCommand;
delete turnOffCommand;
delete remote;
return 0;
}
输出
在上述示例中,我们定义了命令接口 TVCommand,其中声明了一个 execute() 方法来执行电视的相应操作。
具体命令类 TurnOnTVCommand 和 TurnOffTVCommand 实现了 TVCommand 接口,封装了打开和关闭电视的具体操作。
命令发送者 RemoteController 负责持有具体命令对象,并通过调用命令对象的 execute() 方法来执行相应操作。
命令接收者 TVReceiver 定义了电视的操作方法。
在 main 函数中,我们实例化了电视、具体命令对象和遥控器,并进行相应的操作。
六、使用注意事项
命令模式可以将请求发送者和接收者解耦,但也会增加类数量。需要权衡哪些操作适合使用命令模式。
需要注意命令之间的依赖关系,避免形成闭环依赖。
命令模式可以支持撤销操作,可以在命令接口中添加撤销方法来实现。
为了方便处理多个命令的批量执行,可以使用宏命令(Macro Command)来组合多个命令。