当前位置: 首页 > news >正文

21.命令模式(Command Pattern)

定义

命令模式(Command Pattern) 是一种行为型设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求、队列、日志请求以及支持撤销操作等功能。命令模式通过将请求(命令)封装成对象,使得客户端可以将请求发送者与请求接收者解耦,从而更灵活地控制操作的执行。

特性

  • 命令对象:将请求封装成一个命令对象,该命令对象包含了执行的具体操作。
  • Invoker(调用者):调用命令对象的 execute() 方法来执行相应的操作。
  • Receiver(接收者):实际执行命令的对象。
  • Client(客户端):客户端创建命令对象并设置命令的接收者。
  • Command(命令接口):定义命令接口,声明执行操作的抽象方法。

命令模式使得我们能够通过不同的命令对象来执行不同的操作,且操作的执行由调用者控制。

场景

适用场景

  • 请求调用者与请求接收者解耦:当客户端希望通过发送请求来调用不同的操作,而不希望知道具体如何执行时,可以使用命令模式。
  • 需要参数化对象:当需要参数化对象进行命令的请求时,命令模式可以封装请求的参数。
  • 支持撤销和恢复操作:命令模式非常适合实现撤销和恢复操作,通过存储命令对象及其执行过程,能够轻松地实现撤销功能。
  • 支持队列或日志请求:命令模式可以将请求封装成对象,方便将多个命令排入队列或记录日志。

应用场景

  • 图形用户界面(GUI)中的按钮点击事件:通过命令模式将按钮的点击事件封装为命令,使得不同按钮的操作可以被独立控制。
  • 事务管理系统:在事务管理中,命令可以表示一系列操作,通过命令模式进行回滚或恢复。
  • 多操作处理系统:在系统中可能有多个操作(如编辑操作),使用命令模式可以统一管理操作。

类设计

命令模式通常包括以下几个角色:

  1. Command(命令接口):声明执行操作的抽象方法。
  2. ConcreteCommand(具体命令类):实现了 Command 接口,封装了具体的请求与接收者之间的关系。
  3. Receiver(接收者):负责执行与请求相关的操作。
  4. Invoker(调用者):调用命令对象来执行请求。
  5. Client(客户端):客户端创建命令对象并设置接收者。

代码实现

我们设计一个 遥控器操作 的例子。遥控器上有多个按钮,每个按钮对应一个操作(如打开电视、关闭空调等)。我们使用命令模式来封装每个按钮的操作,并通过遥控器(调用者)来执行这些操作。

1. 定义命令接口(Command)

#include <iostream>
#include <string>
using namespace std;// 命令接口
class Command {
public:virtual void execute() = 0;  // 执行命令的接口virtual ~Command() {}
};
  • Command 是命令接口,声明了 execute() 方法,该方法将由具体命令类来实现。

2. 定义具体命令类(ConcreteCommand)

// 电视打开命令
class TVOnCommand : public Command {
private:class TV* tv;  // 接收者(电视)public:TVOnCommand(class TV* tv) : tv(tv) {}void execute() override {tv->turnOn();  // 执行命令:打开电视}
};// 电视关闭命令
class TVOffCommand : public Command {
private:class TV* tv;public:TVOffCommand(class TV* tv) : tv(tv) {}void execute() override {tv->turnOff();  // 执行命令:关闭电视}
};// 空调开命令
class ACOnCommand : public Command {
private:class AC* ac;public:ACOnCommand(class AC* ac) : ac(ac) {}void execute() override {ac->turnOn();  // 执行命令:打开空调}
};// 空调关命令
class ACOffCommand : public Command {
private:class AC* ac;public:ACOffCommand(class AC* ac) : ac(ac) {}void execute() override {ac->turnOff();  // 执行命令:关闭空调}
};
  • 每个命令类(如 TVOnCommand、TVOffCommand 等)都实现了 Command 接口,并封装了具体的操作逻辑。
  • 每个命令类持有一个接收者(例如 TV 或 AC),并在 execute() 方法中调用接收者的方法执行具体的操作。

3. 定义接收者类(Receiver)

class TV {
public:void turnOn() {cout << "TV is turned ON." << endl;}void turnOff() {cout << "TV is turned OFF." << endl;}
};class AC {
public:void turnOn() {cout << "AC is turned ON." << endl;}void turnOff() {cout << "AC is turned OFF." << endl;}
};
  • TV 和 AC 类是接收者,包含了执行具体操作的方法(例如打开电视、关闭空调)。

4. 定义调用者类(Invoker)

class RemoteControl {
private:Command* command;  // 持有命令对象public:void setCommand(Command* command) {this->command = command;  // 设置命令对象}void pressButton() {command->execute();  // 执行命令}
};
  • RemoteControl 类是调用者,持有一个命令对象并在按下按钮时执行该命令。

5. 客户端调用

int main() {// 创建接收者对象TV* tv = new TV();AC* ac = new AC();// 创建命令对象Command* tvOn = new TVOnCommand(tv);Command* tvOff = new TVOffCommand(tv);Command* acOn = new ACOnCommand(ac);Command* acOff = new ACOffCommand(ac);// 创建遥控器RemoteControl* remote = new RemoteControl();// 按下按钮打开电视remote->setCommand(tvOn);remote->pressButton();// 按下按钮关闭电视remote->setCommand(tvOff);remote->pressButton();// 按下按钮打开空调remote->setCommand(acOn);remote->pressButton();// 按下按钮关闭空调remote->setCommand(acOff);remote->pressButton();// 清理内存delete tv;delete ac;delete tvOn;delete tvOff;delete acOn;delete acOff;delete remote;return 0;
}

6. 输出结果

TV is turned ON.
TV is turned OFF.
AC is turned ON.
AC is turned OFF.
  • 客户端通过 RemoteControl 类来控制设备的开关,每次按下按钮时,遥控器都会调用相应命令对象的 execute() 方法,来完成实际的操作。

命令模式的优缺点

优点

  • 解耦发送者和接收者:命令模式将请求的发送者和接收者解耦,客户端不需要知道谁会处理请求,只需要发送命令对象即可。
  • 支持撤销和恢复:命令模式可以很容易实现撤销和恢复操作,命令对象可以保存执行过程,支持回滚。
  • 命令队列和日志:命令可以存储在队列中或日志中,方便管理和回溯。
  • 可扩展性:新命令的增加不会影响现有代码,只需要新增具体命令类即可。

缺点

  • 类的数量增加:每个命令都会对应一个具体的命令类,可能会增加类的数量。
  • 系统结构复杂:使用命令模式时,系统中需要管理多个命令类、调用者和接收者,可能使系统结构变得复杂。

场景

适用场景:

  • GUI事件处理:例如,按钮点击、菜单选择等GUI事件的处理,可以通过命令模式将每个事件封装为命令对象。
  • 任务调度系统:将任务封装成命令对象,通过队列或调度器执行任务。
  • 撤销/恢复功能:如文本编辑器、绘图软件等,需要提供撤销和重做的功能,命令模式能很方便地实现该功能。
  • 宏命令:多个命令可以组合成一个“宏命令”,一起执行。

应用场景:

  1. 文本编辑器的撤销操作:用户进行文本编辑时,编辑操作可以封装为命令对象,撤销时,可以通过命令对象来恢复到之前的状态。
  2. 图形编辑器中的操作:在图形编辑器中,用户可以执行绘制、删除、移动等操作,每个操作都可以封装为命令对象,便于撤销和重做。
  3. 网络请求处理:网络请求可以封装为命令对象,每个请求可以通过命令对象来执行,便于管理请求的执行顺序和状态。

总结

命令模式通过将请求封装成命令对象,使得请求的发送者与接收者解耦。它可以帮助简化系统中的操作,支持撤销/恢复功能,并使得系统更具扩展性。命令模式适用于事件处理、任务调度、宏命令等场景,可以使系统的操作更加灵活和可管理。

http://www.lryc.cn/news/532422.html

相关文章:

  • 深入探索 C++17 特征变量模板 (xxx_v)
  • 【Day32 LeetCode】动态规划DP Ⅴ 完全背包
  • 景区如何打造高质量游览观光车,提高人流量?
  • 【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题
  • 蓝桥杯之c++入门(六)【string(practice)】
  • go的sync包学习
  • 互联网上常见的,ip地址泛播什么意思
  • Linux/C高级(精讲)----shell结构语句、shell数组
  • 14.kafka开机自启动配置
  • 11 享元(Flyweight)模式
  • PHP JSON操作指南
  • 【学习笔记】计算机图形学的几何数学基础知识
  • Python因为网络原因安装依赖库报错
  • 什么是卸荷器?风力发电为什么要用卸荷器
  • SQL Server详细使用教程(包含启动SQL server服务、建立数据库、建表的详细操作) 非常适合初学者
  • 大数据学习之Spark分布式计算框架RDD、内核进阶
  • Unity 加载OSGB(webgl直接加载,无需转换格式!)
  • tcp/ip网络协议,tcp/ip网络协议栈
  • 【Debug】the remote host closed the connection错误信息分析
  • SpringBoot扩展篇:@Scope和@Lazy源码解析
  • “AI隐患识别系统,安全多了道“智能护盾”
  • 通向AGI之路:人工通用智能的技术演进与人类未来
  • 论文阅读:InstanceDiffusion: Instance-level Control for Image Generation
  • 7.攻防世界 wzsc_文件上传
  • 以为是响应式对象丢失导致数据没有回显
  • 来 Gitcode 免费体验 DeepSeek 蒸馏模型,开启 AI 探索新旅程
  • 2.Mkdocs配置说明(mkdocs.yml)【最新版】
  • 云轴科技ZStack+海光DCU:率先推出DeepSeek私有化部署方案
  • 扩增子分析|零模型2——基于βNTI的微生物随机性和确定性装配过程(箱线图和柱状图R中实现)
  • 专题:剑指offer