C++ 设计模式:命令模式(Command Pattern)

链接:C++ 设计模式
链接:C++ 设计模式 - 访问器模式

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

1. 问题分析

在开发中,我们经常需要向某个对象发送请求,但我们希望请求的发送者和接收者解耦。我们还可能需要对请求进行排队、记录日志,甚至支持撤销操作。

命令模式通过将请求封装成一个独立的对象,使得请求的发送者和接收者解耦。每个命令对象都实现一个统一的接口,包含执行请求的方法。这样,我们可以用不同的命令对象对客户进行参数化,并且可以很容易地扩展新的命令。

2.实现步骤

  1. 定义命令接口(Command):声明执行请求的方法。
  2. 实现具体命令类(ConcreteCommand):实现命令接口,执行具体的请求。
  3. 定义接收者类(Receiver):包含执行具体请求的方法。
  4. 定义调用者类(Invoker):持有命令对象,并在某个时刻调用命令对象的执行方法。
  5. 客户端代码(Client):创建具体命令对象,并将其传递给调用者。

3.代码示例

以机器人示例。

3.1.定义命令接口

class Command {public:virtual ~Command() = default;virtual void execute() = 0;
};

3.2.实现具体命令类

// 接收者类:机器人
class Robot {public:void moveForward() { std::cout << "Robot moves forward" << std::endl; }void moveBackward() { std::cout << "Robot moves backward" << std::endl; }void turnLeft() { std::cout << "Robot turns left" << std::endl; }void turnRight() { std::cout << "Robot turns right" << std::endl; }
};

3.3.定义接收者类

// 具体命令类:前进
class MoveForwardCommand : public Command {public:MoveForwardCommand(Robot* robot) : robot_(robot) {}void execute() override { robot_->moveForward(); }private:Robot* robot_;
};
// 具体命令类:后退
class MoveBackwardCommand : public Command {public:MoveBackwardCommand(Robot* robot) : robot_(robot) {}void execute() override { robot_->moveBackward(); }private:Robot* robot_;
};
// 具体命令类:左转
class TurnLeftCommand : public Command {public:TurnLeftCommand(Robot* robot) : robot_(robot) {}void execute() override { robot_->turnLeft(); }private:Robot* robot_;
};
// 具体命令类:右转
class TurnRightCommand : public Command {public:TurnRightCommand(Robot* robot) : robot_(robot) {}void execute() override { robot_->turnRight(); }private:Robot* robot_;
};

3.4.定义调用者类

// 调用者类:遥控器
class RemoteControl {public:void setCommand(Command* command) { command_ = command; }void pressButton() {if (command_) {command_->execute();}}private:Command* command_ = nullptr;
};

3.5.客户端代码

int main() {// 创建接收者对象Robot robot;// 创建具体命令对象MoveForwardCommand moveForwardCommand(&robot);MoveBackwardCommand moveBackwardCommand(&robot);TurnLeftCommand turnLeftCommand(&robot);TurnRightCommand turnRightCommand(&robot);// 创建调用者对象RemoteControl remoteControl;// 设置命令并按下按钮remoteControl.setCommand(&moveForwardCommand);remoteControl.pressButton();remoteControl.setCommand(&moveBackwardCommand);remoteControl.pressButton();remoteControl.setCommand(&turnLeftCommand);remoteControl.pressButton();remoteControl.setCommand(&turnRightCommand);remoteControl.pressButton();return 0;
}

4.C++函数对象

函数对象是一个重载了 operator() 的类,其实例可以像函数一样被调用。函数对象的主要目的是将行为封装到对象中,使得对象可以像函数一样被调用。函数对象强调的是行为的封装和灵活性。

4.1.定义函数对象类

// 函数对象类:前进
class MoveForward {public:MoveForward(Robot* robot) : robot_(robot) {}void operator()() { robot_->moveForward(); }private:Robot* robot_;
};
// 函数对象类:后退
class MoveBackward {public:MoveBackward(Robot* robot) : robot_(robot) {}void operator()() { robot_->moveBackward(); }private:Robot* robot_;
};

4.2.定义调用者类

// 调用者类:遥控器
class RemoteControl {public:void setCommand(std::function<void()> command) { command_ = command; }void pressButton() {if (command_) {command_();}}private:std::function<void()> command_;
};

4.3.客户端代码

int main() {// 创建接收者对象Robot robot;// 创建函数对象MoveForward moveForward(&robot);MoveBackward moveBackward(&robot);// 创建调用者对象RemoteControl remoteControl;// 设置命令并按下按钮remoteControl.setCommand(moveForward);remoteControl.pressButton();remoteControl.setCommand(moveBackward);remoteControl.pressButton();return 0;
}

5.命令模式与函数对象的对比

5.1. 相似点

  1. 封装行为:命令模式和函数对象都可以用于封装行为,使得行为可以像对象一样被传递和调用。
  2. 解耦:两者都可以实现请求的发送者和接收者的解耦。

5.2. 不同点

  1. 设计意图:

    • 命令模式:主要用于将请求封装成对象,从而支持请求的排队、记录日志、撤销和重做等操作。
    • 函数对象:主要用于将行为封装到对象中,使得对象可以像函数一样被调用,强调行为的灵活性和可组合性。
  2. 结构复杂度:

    • 命令模式:通常包含多个角色(命令、具体命令、调用者、接收者),结构较为复杂。
    • 函数对象:通常只需要一个包含 operator() 方法的类,结构较为简单。
  3. 使用场景:

    • 命令模式:适用于需要对请求进行排队、记录日志、支持撤销和重做等操作的场景。
    • 函数对象:适用于需要将行为封装到对象中,并像函数一样调用的场景。

命令模式和函数对象在C++中都可以用于封装行为,但它们在设计意图和使用场景上有所不同。命令模式主要用于将请求封装成对象,从而支持请求的排队、记录日志、撤销和重做等操作;而函数对象主要用于将行为封装到对象中,使得对象可以像函数一样被调用,强调行为的灵活性和可组合性。

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

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

相关文章

html+css+js网页设计 美食 美食4个页面带js

htmlcssjs网页设计 美食 美食4个页面带js 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#…

swagger,showdoc,apifox,Mock 服务,dubbo,ZooKeeper和dubbo的关系

Swagger、ShowDoc 和 Apifox 之间的区别与优势 Swagger、ShowDoc 和 Apifox 都是用于 API 文档管理和测试的工具&#xff0c;但它们各有特色和适用场景。以下是详细的比较&#xff0c;并附上每个工具的具体用法示例。 1. Swagger 特点与优势&#xff1a; 广泛采用: Swagger…

边沿检测电路漏检原因分析

边沿检测电路漏检原因分析 常用结构如下&#xff1a; module edge_detect1( input clk, input signal, output pe, //上升沿 output ne, //下降沿 output de //双边沿 );reg reg1;always(posedge clk) beginreg1 < signal; endassign pe (~reg1) & signal; assign…

嵌入式硬件杂谈(七)IGBT MOS管 三极管应用场景与区别

引言&#xff1a;在现代嵌入式硬件设计中&#xff0c;开关元件作为电路中的重要组成部分&#xff0c;起着至关重要的作用。三种主要的开关元件——IGBT&#xff08;绝缘栅双极型晶体管&#xff09;、MOSFET&#xff08;金属氧化物半导体场效应晶体管&#xff09;和三极管&#…

鸿蒙开发:了解正则表达式

前言 从给出的文本中&#xff0c;按照既定的相关规则&#xff0c;匹配出符合的数据&#xff0c;其中的规则就是正则表达式&#xff0c;使用正则表达式&#xff0c;可以使得我们用简洁的代码就能实现一定复杂的逻辑&#xff0c;比如判断一个邮箱账号是否符合正常的邮箱账号&…

Kafka的acks机制和ISR列表

Kafka 是一个流行的分布式流处理平台&#xff0c;用于构建实时数据流管道和应用程序。在 Kafka 中&#xff0c;acks 机制和 ISR&#xff08;In-Sync Replicas&#xff09;列表是两个重要的概念&#xff0c;它们共同确保消息的持久性和可靠性。 acks 机制 acks 机制是 Kafka 生…

在 Ubuntu 下通过 Docker 部署 Caddy 服务器

嘿&#xff0c;伙伴们&#xff01;今天我们来聊聊如何在 Ubuntu 系统下通过 Docker 部署 Caddy 服务器。Caddy 是一个现代的 Web 服务器&#xff0c;支持自动 HTTPS&#xff0c;简单易用&#xff0c;特别适合快速搭建网站。而 Docker 则是一个让你可以隔离和管理应用的神器。结…

计算机网络•自顶向下方法:网络层介绍、路由器的组成

网络层介绍 网络层服务&#xff1a;网络层为传输层提供主机到主机的通信服务 每一台主机和路由器都运行网络层协议 发送终端&#xff1a;将传输层报文段封装到网络层分组中&#xff0c;发送给边缘路由器路由器&#xff1a;将分组从输入链路转发到输出链路接收终端&#xff1…

Linux top指令

top指令概述 top 是 Linux 系统中用于实时监控系统性能和进程信息的命令&#xff0c;功能强大且灵活。它提供了系统资源的动态视图&#xff0c;包括 CPU、内存、运行中的进程等。 这个指令可以说是Linux中最基本的工具了&#xff0c;用来监视系统的实时运行状态&#xff0c;类…

Qt监控系统放大招/历经十几年迭代完善/多屏幕辅屏预览/多层级设备树/网络登录和回放

一、前言说明 近期对视频监控系统做了比较大的更新升级&#xff0c;主要就是三点&#xff0c;第一点就是增加了辅屏预览&#xff0c;这个也是好多个客户需要的功能&#xff0c;海康的iVMS-4200客户端就有这个功能&#xff0c;方便在多个屏幕打开不同的视频进行查看&#xff0c…

网络原理(六): UDP 协议

目录 1. UDP 协议 1.1 协议特点 1.2 协议报文格式 1.2.1 UDP 长度 1.2.2 校验和 1. UDP 协议 在进行网络编程时, 我们已经对 UDP 协议进行了简单了解. 并且应用层的很多操作, 需要调用传输层的提供的接口, 基于 socket api 来进行完成的. 1.1 协议特点 UDP 协议具有以…

前端页面展示本电脑的摄像头,并使用js获取摄像头列表

可以通过 JavaScript 使用 navigator.mediaDevices.enumerateDevices() 获取电脑上的摄像头列表。以下是一个示例代码&#xff0c;可以展示摄像头列表并选择进行预览。 HTML JavaScript 实现摄像头列表展示和预览 <!DOCTYPE html> <html lang"zh-CN">…

【漫话机器学习系列】028.CP

Mallows’ Cp&#xff1a;标准化公式解析与应用 Mallows’ Cp 是一种常用的模型选择工具&#xff0c;用于在一系列候选模型中权衡拟合度和复杂性&#xff0c;帮助我们选择性能最优的模型。本文将基于其标准化公式展开详细解析&#xff0c;并探讨其应用场景、实现方法、优点与局…

期末算法分析程序填空题

目录 5-1 最小生成树&#xff08;普里姆算法&#xff09; 5-2 快速排序&#xff08;分治法&#xff09; 输入样例&#xff1a; 输出样例&#xff1a; 5-3 归并排序(递归法) 输入样例&#xff1a; 输出样例&#xff1a; 5-4 求解编辑距离问题&#xff08;动态规划法&#xff09;…

深入解析 Conda 安装的默认依赖包及其作用:conda create安装了哪些包(中英双语)

深入解析 Conda 安装的默认依赖包及其作用 当我们使用 Conda 创建新环境时&#xff0c;例如执行命令&#xff1a; conda create -n olmes python3.10Conda 会自动为我们安装一系列基础依赖包&#xff0c;保证 Python 环境能够正常运行。这些包不仅是我们开发的基础工具&#…

Mac、Linux命令

Linux 查本机IP&#xff1a;ip addr 查询文件里符合条件的字符串&#xff1a;grep Mac 查本机IP&#xff1a;ipconfig

Visual Studio 中增加的AI功能

前言&#xff1a; 人工智能的发展&#xff0c;在现在&#xff0c;编程技术的IDE里面也融合了AI的基本操做。本例&#xff0c;以微软的Visual Studio中的人工智能的功能介绍例子。 本例的环境&#xff1a; Visual Studio 17.12 1 AI 智能变量检测&#xff1a; 上图展示了一…

江科大学习笔记之——HAL库点亮一个LED灯

HAL三步走&#xff1a;1.建工程。2.设配置。3.写代码 一.建立工程 HAL库写法 点击FinIsh 2.配置时钟 2 、设置配置参数 把模块.C.h单独设置文件 生产代码 三写代码 控制GPIO就三步 1.RCC时钟使能 2.结构体配置GPIO寄存器 3.控制GPIO值 上面的步骤已经把前两步的配置完成了接下…

Spring MVC (下)小项目实战

1. 加法计算器 需求分析: 客户端输入俩个数,服务端进行相加然后返回结果. 约定前后端交互接口: 接口的概念: 接口⼜叫API&#xff08;ApplicationProgrammingInterface),我们⼀般讲到 接口或者API&#xff0c;指的都是同⼀个东西.是指应⽤程序对外提供的服务的描述,⽤于交换信…

在K8S中,如何查看Pod状态的详情?事件显示cpu不足如何处理?

在Kubernetes中&#xff0c;查看Pod状态的详细通常设计使用kubectl命令行工具&#xff0c;这是kubernetes提供的一个强大的管理工具。以下是如何查看Pod状态详情的步骤&#xff1a; 1. 查看Pod状态详情 列出所有Pod&#xff1a; 使用kubectl get pods命令可以查看集群所有Po…