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

ops/2025/2/22 3:20:47/

命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,从而可以用不同的请求对客户进行参数化,并且支持请求的排队、记录日志以及撤销操作。命令模式的核心思想是将“请求”封装为一个对象,使得可以用不同的请求、队列或者日志来参数化其他对象。

示例:支持撤销操作的计算器

实现一个简单的计算器,它可以执行加法和减法操作,并且支持撤销上一次操作。


1. 定义命令接口

命令接口包含两个方法:execute(执行操作)和 unexecute(撤销操作)。

class Command {
public:virtual ~Command() = default;virtual void execute() = 0;virtual void unexecute() = 0; // 撤销操作
};

2. 创建接收者类

接收者类是实际执行操作的对象。在这里,接收者是一个计算器,它可以执行加法和减法。

class Calculator {
private:int value = 0; // 当前值public:void add(int x) {value += x;std::cout << "Added " << x << ", current value: " << value << std::endl;}void subtract(int x) {value -= x;std::cout << "Subtracted " << x << ", current value: " << value << std::endl;}int getValue() const {return value;}
};

3. 创建具体命令类

我们为加法和减法分别创建具体的命令类。每个命令类都持有一个接收者对象(计算器)和一个操作数。

// 加法命令
class AddCommand : public Command {
private:Calculator& calculator;int operand;public:AddCommand(Calculator& calc, int x) : calculator(calc), operand(x) {}void execute() override {calculator.add(operand);}void unexecute() override {calculator.subtract(operand); // 撤销加法操作}
};// 减法命令
class SubtractCommand : public Command {
private:Calculator& calculator;int operand;public:SubtractCommand(Calculator& calc, int x) : calculator(calc), operand(x) {}void execute() override {calculator.subtract(operand);}void unexecute() override {calculator.add(operand); // 撤销减法操作}
};

4. 创建调用者类

调用者类(Invoker)负责执行命令,并且可以支持撤销操作。我们可以通过一个栈来记录执行过的命令,以便撤销。

#include <stack>
#include <memory>class Invoker {
private:std::stack<std::shared_ptr<Command>> commandHistory; // 命令历史记录public:void executeCommand(std::shared_ptr<Command> command) {if (command) {command->execute();commandHistory.push(command); // 将命令记录到历史中}}void undo() {if (!commandHistory.empty()) {auto lastCommand = commandHistory.top();lastCommand->unexecute(); // 撤销上一次操作commandHistory.pop(); // 从历史记录中移除} else {std::cout << "No commands to undo." << std::endl;}}
};

5. 客户端代码

在客户端代码中,我们创建计算器对象、命令对象,并通过调用者执行和撤销操作。

int main() {Calculator calculator;Invoker invoker;// 创建命令auto addFive = std::make_shared<AddCommand>(calculator, 5);auto subtractThree = std::make_shared<SubtractCommand>(calculator, 3);// 执行加法命令invoker.executeCommand(addFive); // 输出: Added 5, current value: 5// 执行减法命令invoker.executeCommand(subtractThree); // 输出: Subtracted 3, current value: 2// 撤销上一次操作invoker.undo(); // 输出: Added 3, current value: 5// 再次撤销invoker.undo(); // 输出: Subtracted 5, current value: 0// 尝试撤销空历史invoker.undo(); // 输出: No commands to undo.return 0;
}

输出结果

Added 5, current value: 5
Subtracted 3, current value: 2
Added 3, current value: 5
Subtracted 5, current value: 0
No commands to undo.

总结

  1. 封装请求:将加法和减法操作封装为命令对象。
  2. 解耦调用者和接收者:调用者(Invoker)不需要知道具体的操作细节,只需要调用命令对象的 executeunexecute 方法。
  3. 支持撤销操作:通过记录命令历史,可以轻松实现撤销功能。

http://www.ppmy.cn/ops/160408.html

相关文章

Ubuntu18.04设置开机自启动程序

在 Ubuntu 18.04 中&#xff0c;可以通过多种方式设置脚本&#xff08;如 .sh 文件&#xff09;开机自启动。以下是几种常见的方法&#xff1a; ### 方法 1&#xff1a;使用 rc.local&#xff08;适用于简单的脚本&#xff09; 1. **编辑 /etc/rc.local 文件**&#xff1a; …

DeepSeek在linux下的安装部署与应用测试

结合上一篇文章&#xff0c;本篇文章主要讲述在Redhat linux环境下如何部署和使用DeepSeek大模型&#xff0c;主要包括ollama的安装配置、大模型的加载和应用测试。关于Open WebUI在docker的安装部署&#xff0c;Open WebUI官网也提供了完整的docker部署说明&#xff0c;大家可…

python烟花程序代码2.0

效果展示 烟花效果的关键点: 烟花发射:从地面发射出烟花并上升。 爆炸效果:烟花到达最高点后爆炸,产生不同颜色的光点。 颜色变化:爆炸产生的光点有不同的颜色和透明度变化。 粒子扩散:爆炸后的粒子向四面八方扩散,并且随着时间的推移逐渐消失。 我将首先给出一个基本的…

Docker 多阶段构建:优化镜像大小

在 Docker 中&#xff0c;构建镜像时&#xff0c;我们通常会将应用及其所有依赖打包到镜像中。然而&#xff0c;随着时间的推移&#xff0c;镜像的大小会随着依赖项和构建工具的增加而变得越来越大&#xff0c;这不仅增加了存储成本&#xff0c;还会降低容器启动速度。多阶段构…

nlp|微调大语言模型初探索(3),qlora微调deepseek记录

前言 上篇文章记录了使用lora微调llama-1b,微调成功,但是微调llama-8b显存爆炸,这次尝试使用qlora来尝试微调参数体量更大的大语言模型,看看64G显存的极限在哪里。 1.Why QLora? QLoRA 在模型加载阶段通过 4-bit 量化大幅减少了模型权重的显存占用。QLoRA 通过 反量化到 …

14、《SpringBoot+MyBatis集成(2)——进阶配置XML与注解的灵活运用》

SpringBootMyBatis集成进阶配置 - XML与注解的灵活运用 前言 在Spring Boot与MyBatis的集成开发中&#xff0c;开发者常面临XML映射文件与注解两种SQL定义方式的选择&#xff0c;以及复杂场景下的动态SQL、多数据源等进阶需求。本文将从核心配置的灵活性出发&#xff0c;对比X…

一周学会Flask3 Python Web开发-response响应格式

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 在HTTP响应中&#xff0c;数据可以通过多种格式传输。大多数情况下&#xff0c;我们会使用HTML格式&#xff0c;这也是Flask中…

< OS 有关 > Ubuntu 24 SSH 服务器更换端口 in jp/us VPSs

原因&#xff1a; 两台 VPS 的 ssh 端口一直被密码重试&#xff0c; us 这台已经封了 632, jp 这台两周前清过一次 sqlite3 数据&#xff0c;现在赞到 1008 Fail2Ban 是使用 sqlite3 来记录&#xff0c;数据量大后&#xff0c;硬盘的 I/O 会飙升&#xff0c;我有写过一个 app…