命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为一个对象,使你可以用不同的请求对客户进行参数化,还能支持请求的排队、记录日志及撤销操作。这种模式将发送者和接收者解耦,发送者无需知道接收者的具体实现。

命令模式的核心角色

  1. Command(命令接口):声明执行操作的接口(通常是execute()方法)
  2. ConcreteCommand(具体命令):实现命令接口,绑定接收者和具体操作
  3. Receiver(接收者):执行命令所对应的操作,知道如何实施具体行为
  4. Invoker(调用者):要求命令执行请求,持有命令对象
  5. Client(客户端):创建具体命令对象并设置其接收者

C++实现示例

以下以"智能家居控制系统"为例实现命令模式,支持对灯光、电视等设备的操作,以及命令的撤销功能:

#include <iostream>
#include <string>
#include <vector>
#include <memory>// 前向声明接收者类
class Light;
class Television;// 命令接口
class Command {
public:virtual ~Command() = default;virtual void execute() = 0;virtual void undo() = 0;virtual std::string getName() const = 0;
};// 接收者1:灯光
class Light {
private:std::string location;bool isOn;public:Light(std::string loc) : location(std::move(loc)), isOn(false) {}void on() {isOn = true;std::cout << location << "灯光 打开" << std::endl;}void off() {isOn = false;std::cout << location << "灯光 关闭" << std::endl;}bool getState() const {return isOn;}
};// 接收者2:电视
class Television {
private:std::string location;bool isOn;int channel;int volume;public:Television(std::string loc) : location(std::move(loc)), isOn(false), channel(1), volume(5) {}void on() {isOn = true;std::cout << location << "电视 打开" << std::endl;}void off() {isOn = false;std::cout << location << "电视 关闭" << std::endl;}void setChannel(int ch) {channel = ch;std::cout << location << "电视 频道设置为: " << channel << std::endl;}void setVolume(int vol) {volume = vol;std::cout << location << "电视 音量设置为: " << volume << std::endl;}bool getState() const {return isOn;}int getChannel() const {return channel;}int getVolume() const {return volume;}
};// 具体命令1:开灯
class LightOnCommand : public Command {
private:Light* light;bool previousState;  // 用于撤销操作public:LightOnCommand(Light* l) : light(l) {}void execute() override {previousState = light->getState();light->on();}void undo() override {if (previousState) {light->on();} else {light->off();}std::cout << "撤销 " << getName() << std::endl;}std::string getName() const override {return light->getState() ? "开灯" : "关灯";}
};// 具体命令2:关灯
class LightOffCommand : public Command {
private:Light* light;bool previousState;public:LightOffCommand(Light* l) : light(l) {}void execute() override {previousState = light->getState();light->off();}void undo() override {if (previousState) {light->on();} else {light->off();}std::cout << "撤销 " << getName() << std::endl;}std::string getName() const override {return "关灯";}
};// 具体命令3:开电视
class TvOnCommand : public Command {
private:Television* tv;bool previousState;int previousChannel;int previousVolume;public:TvOnCommand(Television* t) : tv(t) {}void execute() override {previousState = tv->getState();previousChannel = tv->getChannel();previousVolume = tv->getVolume();tv->on();tv->setChannel(5);  // 默认打开5频道tv->setVolume(7);   // 默认音量7}void undo() override {if (previousState) {tv->on();tv->setChannel(previousChannel);tv->setVolume(previousVolume);} else {tv->off();}std::cout << "撤销 " << getName() << std::endl;}std::string getName() const override {return "开电视";}
};// 具体命令4:关电视
class TvOffCommand : public Command {
private:Television* tv;bool previousState;public:TvOffCommand(Television* t) : tv(t) {}void execute() override {previousState = tv->getState();tv->off();}void undo() override {if (previousState) {tv->on();} else {tv->off();}std::cout << "撤销 " << getName() << std::endl;}std::string getName() const override {return "关电视";}
};// 调用者:遥控器
class RemoteControl {
private:std::vector<std::unique_ptr<Command>> onCommands;std::vector<std::unique_ptr<Command>> offCommands;std::unique_ptr<Command> undoCommand;  // 记录上一个命令用于撤销public:RemoteControl(int slotCount) {// 初始化命令槽位onCommands.resize(slotCount);offCommands.resize(slotCount);}// 设置命令void setCommand(int slot, std::unique_ptr<Command> onCmd, std::unique_ptr<Command> offCmd) {if (slot >= 0 && slot < onCommands.size()) {onCommands[slot] = std::move(onCmd);offCommands[slot] = std::move(offCmd);}}// 按下开按钮void pressOnButton(int slot) {if (slot >= 0 && slot < onCommands.size() && onCommands[slot]) {onCommands[slot]->execute();undoCommand = std::move(onCommands[slot]);  // 保存命令用于撤销}}// 按下关按钮void pressOffButton(int slot) {if (slot >= 0 && slot < offCommands.size() && offCommands[slot]) {offCommands[slot]->execute();undoCommand = std::move(offCommands[slot]);  // 保存命令用于撤销}}// 按下撤销按钮void pressUndoButton() {if (undoCommand) {undoCommand->undo();} else {std::cout << "没有可撤销的操作" << std::endl;}}
};// 客户端代码
int main() {// 创建接收者Light* livingRoomLight = new Light("客厅");Light* bedroomLight = new Light("卧室");Television* livingRoomTv = new Television("客厅");// 创建命令auto livingRoomLightOn = std::make_unique<LightOnCommand>(livingRoomLight);auto livingRoomLightOff = std::make_unique<LightOffCommand>(livingRoomLight);auto bedroomLightOn = std::make_unique<LightOnCommand>(bedroomLight);auto bedroomLightOff = std::make_unique<LightOffCommand>(bedroomLight);auto tvOn = std::make_unique<TvOnCommand>(livingRoomTv);auto tvOff = std::make_unique<TvOffCommand>(livingRoomTv);// 创建遥控器(调用者),有3个槽位RemoteControl remote(3);// 给遥控器设置命令remote.setCommand(0, std::move(livingRoomLightOn), std::move(livingRoomLightOff));remote.setCommand(1, std::move(bedroomLightOn), std::move(bedroomLightOff));remote.setCommand(2, std::move(tvOn), std::move(tvOff));// 测试操作std::cout << "=== 执行一系列操作 ===" << std::endl;remote.pressOnButton(0);   // 开客厅灯remote.pressOnButton(2);   // 开客厅电视remote.pressOffButton(0);  // 关客厅灯remote.pressOnButton(1);   // 开卧室灯// 测试撤销std::cout << "\n=== 测试撤销操作 ===" << std::endl;remote.pressUndoButton();  // 撤销"开卧室灯"remote.pressUndoButton();  // 撤销"关客厅灯"remote.pressUndoButton();  // 撤销"开客厅电视"// 清理资源delete livingRoomLight;delete bedroomLight;delete livingRoomTv;return 0;
}

代码解析

  1. 命令接口(Command:定义了execute()(执行命令)和undo()(撤销命令)方法,所有具体命令都需实现这两个方法。

  2. 接收者(LightTelevision:实现具体的业务逻辑(如开灯、关灯、开电视等),命令对象会调用这些方法。

  3. 具体命令

    • 每个命令类绑定一个接收者和对应的操作(如LightOnCommand绑定Lighton()方法)
    • 实现execute()方法调用接收者的相应操作,并保存执行前的状态用于undo()
  4. 调用者(RemoteControl

    • 持有多个命令对象(开/关命令对),通过按钮触发命令执行
    • 记录上一个执行的命令,支持undo()操作
  5. 工作流程:客户端创建命令并绑定接收者,调用者通过命令间接操作接收者,实现了发送者与接收者的解耦。

命令模式的优缺点

优点

  • 实现了发送者与接收者的解耦,发送者无需知道接收者的具体实现
  • 容易扩展新命令,符合开放-封闭原则
  • 支持命令的排队、日志记录和撤销操作
  • 可以组合多个命令形成复合命令(宏命令)

缺点

  • 可能导致系统中出现大量具体命令类,增加系统复杂度
  • 命令的撤销/重做功能实现复杂,需要保存历史状态

适用场景

  • 当需要将请求发送者与接收者解耦时
  • 当需要支持命令的撤销、重做操作时
  • 当需要将多个命令组合成复合命令时
  • 当需要实现请求的排队执行或日志记录时

常见应用:

  • 图形界面中的菜单操作、按钮点击
  • 事务处理(支持提交和回滚)
  • 任务调度系统(命令排队执行)
  • 遥控器、游戏手柄等设备的操作抽象

命令模式通过将操作封装为对象,为系统带来了更大的灵活性和可扩展性,特别适合需要支持撤销、日志、事务等功能的场景。

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

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

相关文章

Web攻防-大模型应用LLM搭建接入第三方内容喂养AI插件安全WiKI库技术赋能

知识点&#xff1a; 1、WEB攻防-LLM搭建-AI喂养&安全知识WIKI库 演示案例&#xff1a;WEB攻防-LLM搭建-AI喂养&安全知识WIKI库 使用参考 https://docs.web2gpt.ai/ https://mp.weixin.qq.com/s/qqTOW5Kg1v0uxdSpbfriaA 0、服务器环境&#xff1a;阿里云 Ubuntu22.04 …

图片拼接-动手学计算机视觉8

前言图片拼接&#xff08;image stitching&#xff09;就是将统一场景的不同拍摄出的图片拼接到一起&#xff0c;如图所示就是拼接全景图&#xff0c;是图片拼接的应用之一&#xff0c;手机拍照都有全景拍摄功能仔细观察全景图&#xff0c;寻找它们相似性&#xff0c;图8-2的全…

Web第二次作业

作业一&#xff1a;学校官网1.1学校官网代码如下&#xff1a;​<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">&l…

【CV 目标检测】②R-CNN模型

二、R-CNN网络基础 2.R-CNN模型 2014年提出R-CNN&#xff01;网络&#xff0c;该网络不再使用暴力穷举的方法&#xff0c;而是使用候选区域方法&#xff08;region proposal method&#xff09;创建目标检测的区域来完成目标检测的任务&#xff0c;R-CNN是以深度神经网络为基础…

STM32L051C8与STM32L151C8的主要区别

STM32L051C8与STM32L151C8 有什么区别&#xff1f; LPTIM 有什么特点,为什么STM32L151C8没有LPTIM,而STM32L051C8有1个? 1. STM32L051C8与STM32L151C8的主要区别 STM32L051C8STM32L151C8内核Cortex-M0Cortex-M3主频32MHz32MHz闪存/ SRAM64KB/8KB64KB/16KB工作电压1.65V-3.6V…

【软考中级网络工程师】知识点之网关协议深度剖析

目录一、网关协议基础探秘1.1 网关协议概念1.2 网关协议作用1.3 网关协议分类总览二、内部网关协议&#xff08;IGP&#xff09;深度解析2.1 距离矢量协议2.2 链路状态协议2.3 混合型协议三、外部网关协议&#xff08;EGP&#xff09;探秘3.1 BGP 协议详解3.2 BGP 协议的关键特…

JavaScript 中 call、apply 和 bind 方法的区别与使用

一、核心作用与基础概念这三个方法都用于显式改变函数执行时的 this 指向&#xff0c;解决 JavaScript 中函数上下文动态绑定的问题。1.call()立即执行函数&#xff0c;第一个参数为 this 指向对象&#xff0c;后续参数为逗号分隔的参数列表语法&#xff1a;func.call(thisArg,…

【Android】适配器与外部事件的交互

三三要成为安卓糕手 引入&#xff1a;在上一篇文章中我们完成了新闻展示页面多布局案例的展示&#xff0c;感悟颇多&#xff0c;本篇文章&#xff0c;继续去开发一些新的功能 一&#xff1a;关闭广告 所有的view都可以和我们的用户做交互&#xff0c;循环视图中也给我们提供了相…

MySQL的分析查询语句(EXPLAIN):

目录 基本语法&#xff1a; 各个字段的含义&#xff1a; id&#xff1a; select_type&#xff1a; table&#xff1a; partitions&#xff1a; type&#xff1a; possible_keys&#xff1a; key&#xff1a; key_len&#xff1a; ref&#xff1a; row&#xff1a; …

C++ #if

在 C 中&#xff0c;#if 是 预处理器指令&#xff08;Preprocessor Directive&#xff09;&#xff0c;用于 条件编译&#xff0c;即在编译阶段根据条件决定是否包含某段代码。它通常与 #define、#ifdef、#ifndef、#else 和 #endif 配合使用。基本语法#if 条件表达式// 如果条件…

方案 | 动车底部零部件检测实时流水线检测算法改进

项目背景随着我国高速铁路运营里程突破4.5万公里&#xff0c;动车组日均开行超过8000列次&#xff0c;传统人工巡检方式已无法满足密集运行下的安全检测需求。车底关键部件如制动系统、悬挂装置、牵引电机等长期承受高强度振动和冲击&#xff0c;易产生疲劳裂纹、螺栓松动、部件…

企业收款统计:驱动业务决策的核心引擎设计开发——仙盟创梦IDE

代码完整代码<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><title>黑金风格职员统计</title><style>/* 页面基础样式 - 黑金风格 */body {font-family: Segoe UI, Tahoma, Geneva, Verdana, …

CIAIE 2025上海汽车内外饰展观察:从美学到功能的产业跃迁

在智能化、电动化浪潮推动下&#xff0c;汽车产业的市场格局、技术路线、供应链结构与用户体验正被系统性重塑。汽车感知空间核心的“内外饰件”&#xff0c;正从原本的结构性、功能性部件&#xff0c;逐步跃升为智能化、情感化和差异化体验的重要承载载体&#xff0c;开启了从…

Spring IOC容器在Web环境中的启动奥秘:深入源码解析

一、为何需要关注IOC容器启动&#xff1f;在Java Web开发中&#xff0c;Spring MVC框架的基石正是IOC容器。但你是否思考过&#xff1a;独立的IOC模块如何与Tomcat等Servlet容器协同工作&#xff1f; 其启动过程与Web容器的生命周期深度绑定&#xff0c;这是构建稳定Spring应用…

前端JS处理时间,适用于聊天、操作记录等(包含刚刚、x分钟前、x小时前、x天前)

export default {// 首页时间转化formatDate(val) {var nowDate new Date()var oldDate new Date(val)const Y oldDate.getFullYear()const M oldDate.getMonth() 1const D oldDate.getDate()var diff nowDate.getTime() - oldDate.getTime()var minutes Math.floor(di…

C#---StopWatch类

老方法&#xff0c;想要全面了解和学习一个类必先看文档 微软文档 1.StopWatch 提供一组方法和属性&#xff0c;可用来测量运行时间。 1.1 属性和方法 属性&#xff1a; 方法&#xff1a; 1.2 使用 using System.Diagnostics;namespace Study04_反射专题 {internal cla…

3DTiles转OSGB格式逆向转换方法研究

一、概述 在倾斜摄影的应用领域中&#xff0c;3DTiles与OSGB格式的互转是常见的技术需求。作为专业的GIS处理平台&#xff0c;GISBox凭借其先进的倾斜摄影反切功能&#xff0c;为用户提供了高效、稳定的跨格式数据转换解决方案。 二、3DTiles转OSGB的意义 保留原始几何与纹理…

【门诊进销存出入库管理系统】佳易王医疗器械零售进销存软件:门诊进销存怎么操作?系统实操教程 #医药系统进销存

前言&#xff1a; &#xff08;一&#xff09;试用版获取方式 资源下载路径&#xff1a;进入博主头像主页第一篇文章末尾&#xff0c;点击卡片按钮&#xff1b;或访问左上角博客主页&#xff0c;通过右侧按钮获取详细资料。 说明&#xff1a;下载文件为压缩包&#xff0c;使用…

华为交换机配置文件的相关命令和用法

文章目录一、基本配置命令一、基本配置命令 1、查看当前运行的配置文件 <Huawei>display current-configuration2、配置文件保存 <Huawei>save <Huawei>save vrpcfg-20250623.zip #保存为指定文件名3、查看保存的配置 <Huawei>display saved-configu…

【汽车标定数据】动态优先级线程池在异步多文件解析中的应用

目录 一、需求背景 项目背景&#xff1a;电控数据管理系统优化 优化方案&#xff1a;引入OLAP数据库和动态线程池 线程池性能急需解决的问题 资源过载与闲置的平衡&#xff1a; 优先级处理与公平性&#xff1a; 任务类型适配性&#xff1a; 二、线程池介绍 2.1、线程池…