21.命令模式(Command Pattern)

news2025/2/8 14:43:18

定义

命令模式(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.coloradmin.cn/o/2294818.html

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

相关文章

如何将本地 Node.js 服务部署到宝塔面板:完整的部署指南

文章简介&#xff1a; 将本地开发的 Node.js 项目部署到线上服务器是开发者常见的工作流程之一。在这篇文章中&#xff0c;我将详细介绍如何将本地的 Node.js 服务通过宝塔面板&#xff08;BT 面板&#xff09;上线。宝塔面板是一个强大的服务器管理工具&#xff0c;具有简洁的…

4.3 线性回归的改进-岭回归/4.4分类算法-逻辑回归与二分类/ 4.5 模型保存和加载

4.3.1 带有L2正则化的线性回归-岭回归 岭回归&#xff0c;其实也是一种线性回归&#xff0c;只不过在算法建立回归方程的时候1&#xff0c;加上正则化的限制&#xff0c;从而达到解决过拟合的效果 4.3.1.1 API 4.3.1.2 观察正则化程度的变化&#xff0c;对结果的影响 正则化力…

Mac 部署Ollama + OpenWebUI完全指南

文章目录 &#x1f4bb; 环境说明&#x1f6e0;️ Ollama安装配置1. 安装[Ollama](https://github.com/ollama/ollama)2. 启动Ollama3. 模型存储位置4. 配置 Ollama &#x1f310; OpenWebUI部署1. 安装Docker2. 部署[OpenWebUI](https://www.openwebui.com/)&#xff08;可视化…

工业物联网平台-视频识别视频报警新功能正式上线

前言 视频监控作为中服云工业物联网平台4.0的功能已经上线运行。已为客户服务2年有余&#xff0c;为客户提供多路视频、实时在线监视和控制能力。服务客户实时发现现场、产线、设备出现随机故障、事故等&#xff0c;及时到场处理维修。 视频识别&视频报警新功能当前正式上…

mysql的cpu使用率100%问题排查

背景 线上mysql服务器经常性出现cpu使用率100%的告警&#xff0c; 因此整理一下排查该问题的常规流程。 1. 确认CPU占用来源 检查系统进程 使用 top 或 htop 命令&#xff0c;确认是否是 mysqld 进程导致CPU满载&#xff1a;top -c -p $(pgrep mysqld)2. 实时分析MySQL活动 …

qt6.8安装mysql8.0驱动

qt6.8安装mysql8.0驱动 qt6.8本身是不带mysql驱动。想要在qt里面使用mysql,还是比较麻烦的。需要自己编译驱动 首先下载qt源码&#xff0c;链接Index of /archive/qt/6.8/6.8.1/single 下载mysql对于驱动文件&#xff0c;链接是MySQL :: Download MySQL Connector/C (Archiv…

π0开源了且推出自回归版π0-FAST——打造机器人动作专用的高效Tokenizer:比扩散π0的训练速度快5倍但效果相当

前言 过去的半个多月 对于大模型 deepseek火爆全球&#xff0c;我对其的解读也写成了整整一个系列 详见《火爆全球的DeepSeek系列模型》&#xff0c;涉及对GRPO、MLA、V3、R1的详尽细致深入的解读 某种意义来讲&#xff0c;deepseek 相当于把大模型的热度 又直接拉起来了——…

【算法篇】贪心算法

目录 贪心算法 贪心算法实际应用 一&#xff0c;零钱找回问题 二&#xff0c;活动选择问题 三&#xff0c;分数背包问题 将数组和减半的最小操作次数 最大数 贪心算法 贪心算法&#xff0c;是一种在每一步选择中都采取当前状态下的最优策略&#xff0c;期望得到全局最优…

《金字塔原理》笔记

金字塔原理一书的原理是关于结构化写作的&#xff0c;里面提出一个MECE法则&#xff1a;各个分论点之间要“相互独立、完全穷尽”。 我的总结 写作思路都是总分总。 要凝练最顶部的信息&#xff0c;然后按照三叉树&#xff08;最多四叉树&#xff09;一直分下去。 书中优雅的…

蓝桥杯准备 【入门3】循环结构

素数小算法&#xff08;埃氏筛&&欧拉筛&#xff09; 以下四段代码都是求20以内的所有素数 1.0版求素数 #include<iostream> using namespace std;int main() {int n 20;for(int i2;i<n;i){int j0;for(j2;j<i;j)//遍历i{if(i%j0){break;}}if(ij){cout&l…

MySQL三大日志——binlog、redoLog、undoLog详解

日志是mysql数据库的重要组成部分&#xff0c;记录着数据库运行期间各种状态信息&#xff0c;能帮助我们进行很多容错及分析工作&#xff0c;其中有三大日志与我们这些开发者息息相关&#xff0c;本文将介绍binlog、redoLog、undoLog三种日志&#xff1a; 1. redoLog 1.1 为什么…

SpringAI系列 - 使用LangGPT编写高质量的Prompt

目录 一、LangGPT —— 人人都可编写高质量 Prompt二、快速上手2.1 诗人 三、Role 模板3.1 Role 模板3.2 Role 模板使用步骤3.3 更多例子 四、高级用法4.1 变量4.2 命令4.3 Reminder4.4 条件语句4.5 Json or Yaml 方便程序开发 一、LangGPT —— 人人都可编写高质量 Prompt La…

springboot+vue导入ruoyi项目的框架

一、介绍 RuoYi-Vue版本&#xff0c;采用了前后端分离的单体架构设计软件环境&#xff1a;JDK、Mysql、Redis、Maven、Node技术选型: Spring Boot、Spring Security、MyBatis、Jwt、Vue3、Element-Plus官方地址: https://gitee.com/y_project/RuoYi-Vue 官方推荐的版本如下&a…

Conmi的正确答案——Rider中添加icon作为exe的图标

C#版本&#xff1a;.net 8.0 Rider版本&#xff1a;#RD-243.22562.250&#xff08;非商业使用版&#xff09; 1、添加图标到解决方案下&#xff1a; 2、打开“App.xaml”配置文件&#xff0c;添加配置&#xff1a; <Applicationx:Class"ComTransmit.App"xmlns&q…

360手机刷机 360手机解Bootloader 360手机ROOT

360手机刷机 360手机解Bootloader 360手机ROOT 问&#xff1a;360手机已停产&#xff0c;现在和以后&#xff0c;能刷机吗&#xff1f; 答&#xff1a;360手机&#xff0c;是肯定能刷机的 360手机资源下载网站 360手机-360手机刷机RootTwrp 360os.top 360rom.github.io 一、…

实验3 词法分析(二)

实验3 词法分析(二) [实验目的]&#xff1a; 1 . 熟悉给定的词法分析程序&#xff1b; 2 . 改进词法分析程序。 [实验内容]&#xff1a; 1.尝试多方面改进TEST语言的文法&#xff0c;参考教材附录B词法分析程序TESTscan.c&#xff0c;在此词法分析程序的基础上改进程序&#x…

VsCode创建VUE项目

1. 首先安装Node.js和npm 通过网盘分享的文件&#xff1a;vsCode和Node&#xff08;本人电脑Win11安装&#xff09; 链接: https://pan.baidu.com/s/151gBWTFZh9qIDS9XWMJVUA 提取码: 1234 它们是运行和构建Vue.js应用程序所必需的。 1.1 Node安装&#xff0c;点击下一步即可 …

【自开发工具介绍】SQLSERVER的ImpDp和ExpDp工具04

SQLSERVER的ImpDp和ExpDp工具演示 1、指定某些表作为导出对象外 (-exclude_table) 验证用&#xff1a;导出的表&#xff0c;导入到新的数据库 2、指定某些表作为导出对象外 (-exclude_table) 支持模糊检索&#xff0c;可以使用星号 以s开头的表作为导出对象外&#xff0c;…

国内知名Deepseek培训师培训讲师唐兴通老师讲授AI人工智能大模型实践应用

课程名称 《Deepseek人工智能大模型实践应用》 课程目标 全面了解Deepseek人工智能大模型的技术原理、功能特点及应用场景。 熟练掌握Deepseek大模型的提示词工程技巧&#xff0c;能够编写高质量的提示词。 掌握Deepseek大模型在办公、营销等领域的应用方法&#xff0c;提升…

【C语言标准库函数】指数与对数函数:exp(), log(), log10()

目录 一、头文件 二、函数简介 2.1. exp(double x) 2.2. log(double x) 2.3. log10(double x) 三、函数实现&#xff08;概念性&#xff09; 3.1. exp(double x) 的模拟实现 3.2. log(double x) 和 log10(double x) 的模拟实现 四、注意事项 4.1. exp(double x) 的注…