Qt C++设计模式->命令模式

命令模式(Command Pattern)是一种行为型设计模式,它将一个请求封装为一个对象,从而使你可以用不同的请求对客户端进行参数化,对请求排队或记录请求日志,并支持可撤销的操作。命令模式通过将请求的发送者与执行者解耦,赋予了系统更强的灵活性和可扩展性。

命令模式的应用场景

命令模式常用于以下场景:

  • 撤销操作:可以将命令封装起来,支持撤销和恢复操作。

  • 任务队列:可以对命令进行排队处理,例如任务调度系统。

  • 宏命令:可以将一组命令打包为一个复杂的操作,例如在游戏或复杂应用中执行一系列操作。

命令模式允许请求发送者和接收者完全解耦,发送者只需负责将命令发出,接收者如何处理命令并不影响发送者的操作。

命令模式的核心结构

命令模式的关键参与者有以下几种:

  1. 命令接口(Command):定义了执行请求的方法,所有具体命令类都实现该接口。

  2. 具体命令(Concrete Command):实现了命令接口,持有对接收者对象的引用,执行具体的操作。

  3. 接收者(Receiver):执行命令实际逻辑的对象。

  4. 调用者(Invoker):负责调用命令,通常包含一个命令对象的引用。

命令模式示例代码

假设你在开发一个智能家居系统,其中有灯光设备,用户可以通过不同的命令来打开或关闭灯光。命令模式将这些操作封装为对象,允许你对命令进行操作(如记录、撤销等)。

#include <QDebug>
#include <QString>// 接收者类:灯
class Light {
public:void turnOn() {qDebug() << "The light is on";}void turnOff() {qDebug() << "The light is off";}
};// 命令接口
class Command {
public:virtual void execute() = 0;  // 执行命令virtual void undo() = 0;     // 撤销命令virtual ~Command() = default;
};// 具体命令类:打开灯光命令
class LightOnCommand : public Command {
private:Light* light;  // 持有接收者对象public:LightOnCommand(Light* light) : light(light) {}void execute() override {light->turnOn();  // 执行打开灯光的操作}void undo() override {light->turnOff();  // 撤销打开灯光的操作}
};// 具体命令类:关闭灯光命令
class LightOffCommand : public Command {
private:Light* light;  // 持有接收者对象public:LightOffCommand(Light* light) : light(light) {}void execute() override {light->turnOff();  // 执行关闭灯光的操作}void undo() override {light->turnOn();  // 撤销关闭灯光的操作}
};// 调用者类:遥控器
class RemoteControl {
private:Command* command;  // 持有当前命令public:void setCommand(Command* command) {this->command = command;  // 设置要执行的命令}void pressButton() {if (command) {command->execute();  // 执行命令}}void pressUndo() {if (command) {command->undo();  // 撤销命令}}
};// 使用示例
int main() {// 创建接收者Light* livingRoomLight = new Light();// 创建具体命令Command* lightOn = new LightOnCommand(livingRoomLight);Command* lightOff = new LightOffCommand(livingRoomLight);// 创建调用者RemoteControl* remote = new RemoteControl();// 通过遥控器打开灯remote->setCommand(lightOn);remote->pressButton();  // 输出:The light is onremote->pressUndo();    // 输出:The light is off// 通过遥控器关闭灯remote->setCommand(lightOff);remote->pressButton();  // 输出:The light is offremote->pressUndo();    // 输出:The light is on// 清理内存delete lightOn;delete lightOff;delete livingRoomLight;delete remote;return 0;
}

代码解析

  • Light类:这是接收者类,包含具体的逻辑操作(打开和关闭灯光)。

  • Command接口:定义了executeundo方法,所有的具体命令都必须实现这些方法。

  • LightOnCommand和LightOffCommand类:具体命令类,分别封装了打开和关闭灯光的操作,内部持有接收者Light对象。

  • RemoteControl类:这是调用者,负责调用命令。它可以设置命令并执行或撤销该命令。

  • 客户端代码:客户端通过将不同的命令设置给RemoteControl,可以执行不同的操作,并支持撤销命令。

命令模式的优点

  • 解耦请求发送者和接收者:命令模式将请求发送者与接收者完全解耦,发送者只知道如何发出请求,而不需要知道如何处理请求。

  • 支持撤销和重做:由于命令对象封装了具体操作,命令模式天然支持撤销和重做操作。

  • 扩展性强:可以轻松添加新命令,而不需要改变现有代码。只需要添加新的命令类,实现命令接口即可。

  • 支持宏命令:命令模式可以组合多个命令,从而实现复杂操作的宏命令。

命令模式的缺点

  • 命令类增多:对于每个不同的请求,都需要定义一个新的命令类,可能会导致命令类数量过多,增加系统复杂性。

  • 增加内存开销:因为每一个请求都需要封装为一个对象,可能会导致内存开销增加,尤其是当命令比较复杂时。

适合使用命令模式的情况

  • 需要对请求排队、记录日志或撤销操作:例如任务调度系统、日志系统、编辑器中的撤销操作等。

  • 需要参数化请求:可以通过不同的命令对象,将请求封装为参数传递给调用者。

  • 需要将一系列操作封装为宏命令:例如在复杂应用中(如游戏、绘图软件等),可以将一组操作封装为一个宏命令,并在某个时刻统一执行。

Qt中的命令模式应用

在Qt开发中,命令模式可以用于事件处理、撤销操作、任务调度等场景。例如,在图形界面应用中,命令模式可以用于封装对控件的操作,从而实现撤销/重做功能。此外,Qt的信号与槽机制也具有类似命令模式的思想,信号发出时由槽来处理事件,从而解耦了事件发送者与处理者。

命令模式通过将请求封装为对象,提供了灵活的请求处理机制,尤其适合需要对请求进行管理、撤销或组合的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/880955.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

protobuf 讲解

一、序列化概念回顾 二、什么是PB 将结构化数据进行序列化的一种方式 三、PB的特点 语言无关、平台无关&#xff1a;即PB支持Java&#xff0c;C、Python等多种语言。支持多个平台 高效&#xff1a;即比XML更小&#xff0c;更快&#xff0c;更为简单。 扩展性、兼容性好&am…

rabbitMq------客户端模块

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言消费者模块信道管理模块管理的字段提供的接口 信道内存管理连接管理类 前言 在RabbitMQ中&#xff0c;提供服务的是信道&#xff0c;因此在客⼾端的实现中&…

WPF之UI进阶--控件样式与样式模板及词典

WPF的优势之一就是能够更加容易快捷的对窗体和控件的外面进行改造&#xff0c;换句话说&#xff0c;那就是UI设计个性化更加容易。主要是借助了样式、模板及词典来实现的。那么本篇博文就一一对他们进行介绍。 文章目录 一、样式1: 定义样式2: 使用Setter设置属性关于Property和…

Python知识点:如何使用Edge Impulse与Python进行机器学习模型部署

开篇&#xff0c;先说一个好消息&#xff0c;截止到2025年1月1日前&#xff0c;翻到文末找到我&#xff0c;赠送定制版的开题报告和任务书&#xff0c;先到先得&#xff01;过期不候&#xff01; 使用Edge Impulse与Python进行机器学习模型部署 在物联网和边缘计算领域&#x…

java线程池参数设置原则

线程池参数设置原则 1 如何为线程池设置合适的线程参数&#xff1f; 目前根据一些开源框架&#xff0c;设置多少个线程数量通常是根据应用的类型**&#xff1a;I/O 密集型、CPU 密集型。** I/O密集型 I/O密集型的场景在开发中比较常见&#xff0c;比如像 MySQL数据库读写、文…

C或C++判断指针是否指向同一块内存

有时需要判断指针是否指同一块内存&#xff0c;例如设计字符串时&#xff1a; &#xff08;1&#xff09;insert函数 &#xff08;2) replace函数 &#xff08;3&#xff09;assign函数 难点是迭代器&#xff0c;判断是否同一个迭代器时&#xff0c;需要你在设计迭代器时加…

Kubernetes-环境篇-01-mac开发环境搭建

1、brew安装 参考知乎文章&#xff1a;https://zhuanlan.zhihu.com/p/111014448 苹果电脑 常规安装脚本&#xff08;推荐 完全体 几分钟安装完成&#xff09; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"苹果电脑 极…

Rstudio:强大的R语言集成开发环境(IDE)

Rstudio 应该是 R 语言使用的标配&#xff0c;尽管 Rstudio 的母公司 Posit 推出了新一代的集成开发环境 Positron&#xff0c;但其还处于开发阶段。作为用户不妨让其成熟后再使用&#xff0c;现阶段还是 Rstudio 更稳定。 如果你在生物信息学或统计学领域工作&#xff0c;R语言…

Python | Leetcode Python题解之第455题分发饼干

题目&#xff1a; 题解&#xff1a; class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:g.sort()s.sort()m, n len(g), len(s)i j count 0while i < m and j < n:while j < n and g[i] > s[j]:j 1if j < n:count 1i …

uni-app - - - - -vue3使用i18n配置国际化语言

uni-app - - - - -使用i18n配置国际化语言 1. 安装vue-i18n2. 配置文件2.1 创建如下文件2.2 文件配置2.3 main文件导入i18n 3. 页面内使用3.1 template内直接使用3.2 变量接收使用 1. 安装vue-i18n npm install vue-i18n --save2. 配置文件 2.1 创建如下文件 locales文件夹里…

水泵模块(5V STM32)

目录 一、介绍 二、传感器原理 1.尺寸介绍 2.继电器控制水泵电路原理图 三、程序设计 main.c文件 bump.h文件 bump.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 水泵模块(bump)通常是指用于液体输送系统的组件&#xff0c;它负责将水或其他流体从低处提…

PHP常用的超全局变量(8个)

在PHP中&#xff0c;超全局变量是一种特殊的变量类型&#xff0c;它们在全部作用域中始终可用&#xff0c;无需使用global关键字来访问。这些变量提供了在PHP脚本中访问和操作各种数据和环境信息的便捷方式。以下是PHP中常用的8个超全局变量的详细介绍&#xff1a; 1. $GLOBAL…

四.网络层(上)

目录 4.1网络层功能概述 4.2 SDN基本概念 4.3 路由算法与路由协议 4.3.1什么是路由协议&#xff1f; 4.3.2什么是路由算法&#xff1f; 4.3.3路由算法分类 (1)静态路由算法 (2)动态路由算法 ①全局性 OSPF协议与链路状态算法 ②分散性 RIP协议与距离向量算法 4.3.…

【C语言】内存函数的使用和模拟实现

文章目录 一、memcpy的使用和模拟实现二、memmove的使用和模拟实现三、memset的使用四、memcmp的使用 一、memcpy的使用和模拟实现 在之前我们学习了使用和模拟实现strncpy函数&#xff0c;它是一个字符串函数&#xff0c;用来按照给定的字节个数来拷贝字符串&#xff0c;那么问…

Javascript数组研究03_手写实现_fill_filter_find_findIndex_findLast_findLastIndex

6 Array.fill() 6.1 基本介绍 fill() 方法用一个固定值填充一个数组中从起始索引&#xff08;默认为 0&#xff09;到终止索引&#xff08;默认为 array.length&#xff09;内的全部元素。它返回修改后的数组。 fill(value) fill(value, start) fill(value, start, end)输入…

【本地免费】SimpleTex 图像识别latex公式

文章目录 相关教程相关文献安装教程 由于mathpix开始收费了&#xff0c;于是本文将介绍一款目前本地免费的SimpleTex工具 相关教程 【超详细安装教程】LaTeX-OCR 图像识别latex公式&#xff08;开源免费&#xff09;_latex图片识别-CSDN博客 相关文献 SimpleTex主页——致力…

如何在微信小程序中实现分包加载和预下载

如何在微信小程序中实现分包加载和预下载 概述 微信小程序提供了分包加载和预下载功能&#xff0c;这有助于优化应用的加载时间&#xff0c;提升用户体验。本文将详细介绍如何在微信小程序中配置分包加载和预下载。 步骤一&#xff1a;配置分包加载 修改app.json文件&#x…

Dijkstra算法,动态规划和滑动窗口

一&#xff1a;最小花费 题目链接&#xff1a;1928. 规定时间内到达终点的最小花费 - 力扣&#xff08;LeetCode&#xff09; &#xff08;1&#xff09;Dijkstra算法 理解问题&#xff1a;首先&#xff0c;我们需要理解问题的核心是找到一条从城市 0 到城市 n-1 的路径&…

数据结构双向链表和循环链表

目录 一、循环链表二、双向链表三、循环双向链表 一、循环链表 循环链表就是首尾相接的的链表&#xff0c;就是尾节点的指针域指向头节点使整个链表形成一个循环&#xff0c;这就弥补了以前单链表无法在后面某个节点找到前面的节点&#xff0c;可以从任意一个节点找到目标节点…

web笔记

<form method"POST" action"{{ url_for(register) }}"><label for"username">用户名:</label><input type"text" id"username" name"username" required><br><label for"p…