21.命令模式(Command Pattern)
定义
命令模式(Command Pattern) 是一种行为型设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求、队列、日志请求以及支持撤销操作等功能。命令模式通过将请求(命令)封装成对象,使得客户端可以将请求发送者与请求接收者解耦,从而更灵活地控制操作的执行。
特性
- 命令对象:将请求封装成一个命令对象,该命令对象包含了执行的具体操作。
- Invoker(调用者):调用命令对象的 execute() 方法来执行相应的操作。
- Receiver(接收者):实际执行命令的对象。
- Client(客户端):客户端创建命令对象并设置命令的接收者。
- Command(命令接口):定义命令接口,声明执行操作的抽象方法。
命令模式使得我们能够通过不同的命令对象来执行不同的操作,且操作的执行由调用者控制。
场景
适用场景
- 请求调用者与请求接收者解耦:当客户端希望通过发送请求来调用不同的操作,而不希望知道具体如何执行时,可以使用命令模式。
- 需要参数化对象:当需要参数化对象进行命令的请求时,命令模式可以封装请求的参数。
- 支持撤销和恢复操作:命令模式非常适合实现撤销和恢复操作,通过存储命令对象及其执行过程,能够轻松地实现撤销功能。
- 支持队列或日志请求:命令模式可以将请求封装成对象,方便将多个命令排入队列或记录日志。
应用场景
- 图形用户界面(GUI)中的按钮点击事件:通过命令模式将按钮的点击事件封装为命令,使得不同按钮的操作可以被独立控制。
- 事务管理系统:在事务管理中,命令可以表示一系列操作,通过命令模式进行回滚或恢复。
- 多操作处理系统:在系统中可能有多个操作(如编辑操作),使用命令模式可以统一管理操作。
类设计
命令模式通常包括以下几个角色:
- Command(命令接口):声明执行操作的抽象方法。
- ConcreteCommand(具体命令类):实现了 Command 接口,封装了具体的请求与接收者之间的关系。
- Receiver(接收者):负责执行与请求相关的操作。
- Invoker(调用者):调用命令对象来执行请求。
- 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事件的处理,可以通过命令模式将每个事件封装为命令对象。
- 任务调度系统:将任务封装成命令对象,通过队列或调度器执行任务。
- 撤销/恢复功能:如文本编辑器、绘图软件等,需要提供撤销和重做的功能,命令模式能很方便地实现该功能。
- 宏命令:多个命令可以组合成一个“宏命令”,一起执行。
应用场景:
- 文本编辑器的撤销操作:用户进行文本编辑时,编辑操作可以封装为命令对象,撤销时,可以通过命令对象来恢复到之前的状态。
- 图形编辑器中的操作:在图形编辑器中,用户可以执行绘制、删除、移动等操作,每个操作都可以封装为命令对象,便于撤销和重做。
- 网络请求处理:网络请求可以封装为命令对象,每个请求可以通过命令对象来执行,便于管理请求的执行顺序和状态。
总结
命令模式通过将请求封装成命令对象,使得请求的发送者与接收者解耦。它可以帮助简化系统中的操作,支持撤销/恢复功能,并使得系统更具扩展性。命令模式适用于事件处理、任务调度、宏命令等场景,可以使系统的操作更加灵活和可管理。
相关文章:
21.命令模式(Command Pattern)
定义 命令模式(Command Pattern) 是一种行为型设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求、队列、日志请求以及支持撤销操作等功能。命令模式通过将请求(命令)封装成对象,使…...
深入探索 C++17 特征变量模板 (xxx_v)
文章目录 一、C++类型特征的前世今生二、C++17特征变量模板闪亮登场三、常见特征变量模板的实际应用(一)基本类型判断(二)指针与引用判断四、在模板元编程中的关键作用五、总结与展望在C++的持续演进中,C++17带来了许多令人眼前一亮的特性,其中特征变量模板(xxx_v)以其…...
【Day32 LeetCode】动态规划DP Ⅴ 完全背包
一、动态规划DP Ⅴ 完全背包 1、完全背包理论 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和…...
景区如何打造高质量游览观光车,提高人流量?
景区如何打造高质量游览观光车,提高人流量? 在旅游业蓬勃发展的今天,各大景区迎来了前所未有的游客热潮。尤其是在春节、五一、国庆等节假日期间,游客数量更是激增。作为景区交通的重要组成部分,游览观光车不仅承载着…...
【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题
【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题 零、起因 最近在使用Ubuntu虚拟机编译ARM程序,解压ARM的GCC后想要启动,报“没有那个文件或目录”,但是文件确实存在,环境配置也检查过了没问题,本文记…...
蓝桥杯之c++入门(六)【string(practice)】
目录 练习1:标题统计方法1:一次性读取整行字符,然后统计方法2:按照单词读取小提示: 练习2:石头剪子布练习3:密码翻译练习4:文字处理软件练习5:单词的长度练习6࿱…...
go的sync包学习
包含了sync.Mutex,sync.RWMutex,sync.Cond,sync.Map,sync.Once等demo sync.Mutex //讲解mutex import ("fmt""math/rand""sync""time" )type Toilet struct {m sync.Mutex } type Person struct {Name string }var DateTime "2…...
互联网上常见的,ip地址泛播什么意思
互联网上常见的,ip地址泛播什么意思! 泛播通过将IP地址广播发送到网络中的所有设备,使得这些设备能够接收到相关信息。例如,DHCP服务器在局域网中广播提供IP地址的请求,以便新设备能够获取一个可用的IP地址。此外&…...
Linux/C高级(精讲)----shell结构语句、shell数组
shell脚本 功能性语句 test 可测试对象三种:字符串 整数 文件属性 每种测试对象都有若干测试操作符 1)字符串的测试: s1 s2 测试两个字符串的内容是否完全一样 s1 ! s2 测试两个字符串的内容是否有差异 -z s1 测试s1 字符串的长度是…...
14.kafka开机自启动配置
要在Linux(RHEL7.7)系统中设置kafka开机自启动,可以创建一个系统服务单元文件。以下是为详细配置部署,假设你已经安装了kafka并且可以通过kafka-server-start.sh命令启动它。 1.进入/lib/systemd/system目录 命令: cd /lib/systemd/system…...
11 享元(Flyweight)模式
享元模式 1.1 分类 (对象)结构型 1.2 提出问题 做一个车管所系统,将会产生大量的车辆实体,如果每一个实例都保存自己的所有信息,将会需要大量内存,甚至导致程序崩溃。 1.3 解决方案 运用共享技术有效…...
PHP JSON操作指南
PHP JSON操作指南 概述 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。PHP作为一门流行的服务器端脚本语言,支持对JSON数据进行读取、编写和解析。本文将…...
【学习笔记】计算机图形学的几何数学基础知识
3D坐标系 左手系和右手系 点 x,y,z与w(齐次坐标) 矩阵 第一个下标表示行号,第二个下标表示列号。矩阵乘法不满足交换律矩阵乘法=矩阵合并一个矩阵乘以它的逆矩阵=单位矩阵变化矩阵 平移矩阵 缩放矩阵 除了可以缩放, 还可以利用缩放,在给定右手系的情况确定左手系…...
Python因为网络原因安装依赖库报错
现象 在终端运行以下指令 pip install pyautogui pillow keyboard 出现报错,终端信息如下: PS D:\code\Python> pip install pyautogui pillow keyboard Collecting pyautoguiUsing cached PyAutoGUI-0.9.54.tar.gz (61 kB)Installing build depe…...
什么是卸荷器?风力发电为什么要用卸荷器
目前市场上,那些功率低于400W的小型风力发电机,普遍缺乏刹车、稳速或限速机制。只要有足够的风力,发电机便会开始转动并产生电力。风力越强,转速就越快,这可能导致发电机因转速过高而损坏,甚至发生风机头飞…...
SQL Server详细使用教程(包含启动SQL server服务、建立数据库、建表的详细操作) 非常适合初学者
SQL Server详细使用教程(包含启动SQL server服务、建立数据库、建表的详细操作) 非常适合初学者 文章目录 目录 前言 一、启动SQL server服务的三种方法 1.不启动SQL server服务的影响 2.方法一:利用cmd启动SQL server服务 3.方法二:利用SQL Serv…...
大数据学习之Spark分布式计算框架RDD、内核进阶
一.RDD 28.RDD_为什么需要RDD 29.RDD_定义 30.RDD_五大特性总述 31.RDD_五大特性1 32.RDD_五大特性2 33.RDD_五大特性3 34.RDD_五大特性4 35.RDD_五大特性5 36.RDD_五大特性总结 37.RDD_创建概述 38.RDD_并行化创建 演示代码: // 获取当前 RDD 的分区数 Since ( …...
Unity 加载OSGB(webgl直接加载,无需转换格式!)
Unity webgl加载倾斜摄影数据 前言效果图后续不足 前言 Unity加载倾斜摄影数据,有很多的插件方便好用,但是发布到网页端均失败,因为webgl 的限制,IO读取失效。 前不久发现一个开源项目: UnityOSGB-main 通过两种方式在 Unity 中…...
tcp/ip网络协议,tcp/ip网络协议栈
TCP/IP网络协议和TCP/IP网络协议栈是互联网通信的基石,它们定义了电子设备如何连入因特网以及数据如何在它们之间传输的标准。以下是对TCP/IP网络协议和TCP/IP网络协议栈的详细解释: 一、TCP/IP网络协议 TCP/IP(Transmission Control Proto…...
【Debug】the remote host closed the connection错误信息分析
出现的情况说明:QT软件。刚开始都可以连接成功 之后连接 断开几次 就会出现连接失败 错误信息是the remote host closed the connection。the remote host closed the connection广泛原因分析 这个错误通常意味着远端 STM32 服务器主动关闭了连接。可能的原因包括&a…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
