【C++类和数据抽象】消息处理示例(1):从设计模式到实战应用

目录

一、数据抽象概述

二、消息处理的核心概念

2.1 什么是消息处理?

2.2 消息处理的核心目标

三、基于设计模式的消息处理实现

3.1 观察者模式(Observer Pattern)

3.2 命令模式(Command Pattern)

四、实战场景:GUI 框架中的消息处理

4.1 模拟 Qt 信号槽机制

五、高级主题:多线程消息队列

5.1 基于队列的异步消息处理

六、消息处理的最佳实践

6.1 解耦优先

6.2 线程安全

6.3 错误处理

6.4 性能优化

七、总结


在 C++ 的复杂系统开发中,消息处理是实现组件解耦、异步通信和事件驱动的核心机制。无论是 GUI 框架中的按钮点击响应,还是分布式系统中的模块通信,消息处理都扮演着关键角色。本文将围绕设计模式(如观察者模式、命令模式)和实战场景(如 GUI 事件、多模块通信),深入探讨 C++ 中消息处理的实现方式。

一、数据抽象概述

数据抽象是一种编程技术,它允许我们定义数据类型,同时隐藏其内部实现细节。意味着,我们只需关注数据对象能做什么,而不是它们是如何做的。在C++中,数据抽象主要通过类和对象实现。类定义了数据成员和成员函数,其中数据成员用于存储数据,而成员函数用于操作这些数据。通过将数据成员设置为私有(private),确保了它们只能通过类的公共接口(public成员函数)访问。

数据抽象具有多个优点:

  • 安全性:数据抽象可以防止不恰当的数据访问,从而保护数据的安全性。
  • 简化复杂性:允许我们处理复杂系统时,只关注其高层次的抽象,而不是底层细节。
  • 易于维护和修改:由于实现细节被隐藏,修改内部实现时不会影响到使用这些数据的其他部分。
  • 可重用性:抽象数据类型可以被重复使用,从而提高代码的可重用性。

二、消息处理的核心概念

2.1 什么是消息处理?

消息是组件间传递的信息载体,包含事件类型、数据参数等内容。
消息处理指接收消息并执行相应逻辑的过程,通常涉及:

  • 消息发送者:产生消息的组件(如按钮点击、传感器数据更新)。
  • 消息接收者:处理消息的组件(如事件处理器、业务逻辑模块)。
  • 消息通道:连接发送者与接收者的通信链路(如函数调用、队列、信号槽)。

2.2 消息处理的核心目标

  • 解耦组件:发送者与接收者无需直接依赖,提高系统灵活性。
  • 异步通信:支持非阻塞消息传递,提升系统响应速度。
  • 可扩展性:方便添加新的消息类型或处理逻辑。

三、基于设计模式的消息处理实现

3.1 观察者模式(Observer Pattern)

①模式原理

  • 角色
    • 主题(Subject):维护观察者列表,发送消息。
    • 观察者(Observer):接收消息并执行处理逻辑。
  • 核心机制:主题与观察者通过抽象接口解耦,主题发送消息时自动通知所有注册的观察者。

②代码示例:按钮点击事件处理

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm> // 使用 std::remove_if// 抽象观察者接口
class ButtonObserver {
public:// 纯虚函数,具体观察者需要实现该函数来处理按钮点击事件virtual void OnButtonClick() = 0;// 虚析构函数,确保在通过基类指针删除派生类对象时能正确调用派生类的析构函数virtual ~ButtonObserver() = default;
};// 具体观察者:日志记录器
class LogObserver : public ButtonObserver {
public:// 实现 OnButtonClick 函数,处理日志记录void OnButtonClick() override {std::cout << "Button clicked: Logging event..." << std::endl;}
};// 具体观察者:业务处理器
class BusinessObserver : public ButtonObserver {
public:// 实现 OnButtonClick 函数,处理业务逻辑void OnButtonClick() override {std::cout << "Button clicked: Processing business logic..." << std::endl;}
};// 主题:按钮类
class Button {
public:// 向观察者列表中添加观察者void AddObserver(std::shared_ptr<ButtonObserver> observer) {if (observer) {observers_.push_back(observer);} else {std::cerr << "Error: Attempt to add a null observer." << std::endl;}}// 从观察者列表中移除指定的观察者void RemoveObserver(std::shared_ptr<ButtonObserver> observer) {if (observer) {auto newEnd = std::remove_if(observers_.begin(), observers_.end(), [&observer](const std::shared_ptr<ButtonObserver>& obs) {return obs == observer;});if (newEnd != observers_.end()) {observers_.erase(newEnd, observers_.end());} else {std::cerr << "Error: Observer not found in the list." << std::endl;}} else {std::cerr << "Error: Attempt to remove a null observer." << std::endl;}}// 模拟按钮点击,发送消息给所有注册的观察者void Click() {std::cout << "Button clicked: Notifying observers..." << std::endl;for (const auto& observer : observers_) {if (observer) {observer->OnButtonClick();} else {std::cerr << "Error: Found a null observer in the list." << std::endl;}}}private:// 存储观察者的列表std::vector<std::shared_ptr<ButtonObserver>> observers_;
};// 主函数:测试消息处理流程
int main() {Button button;auto logObserver = std::make_shared<LogObserver>();auto businessObserver = std::make_shared<BusinessObserver>();button.AddObserver(logObserver);button.AddObserver(businessObserver);button.Click(); // 触发消息发送return 0;
}

3.2 命令模式(Command Pattern)

①模式原理

  • 角色
    • 命令(Command):封装消息内容和处理逻辑。
    • 调用者(Invoker):触发命令执行。
    • 接收者(Receiver):实际执行命令的组件。
  • 核心机制:将 “消息” 封装为命令对象,支持动态添加、撤销命令,实现异步消息处理。

②代码示例:文件操作命令队列

#include <iostream>
#include <vector>
#include <memory>// 抽象命令接口
class FileCommand {
public:virtual void Execute() = 0;virtual ~FileCommand() = default;
};// 具体命令:创建文件
class CreateFileCommand : public FileCommand {
public:CreateFileCommand(const std::string& filename) : filename_(filename) {}void Execute() override {std::cout << "Creating file: " << filename_ << std::endl;// 实际文件创建逻辑}private:std::string filename_;
};// 具体命令:删除文件
class DeleteFileCommand : public FileCommand {
public:DeleteFileCommand(const std::string& filename) : filename_(filename) {}void Execute() override {std::cout << "Deleting file: " << filename_ << std::endl;// 实际文件删除逻辑}private:std::string filename_;
};// 命令调用者:消息队列
class CommandQueue {
public:void AddCommand(std::shared_ptr<FileCommand> command) {commands_.push_back(command);}void ProcessCommands() { // 批量处理消息for (const auto& command : commands_) {command->Execute();}commands_.clear();}private:std::vector<std::shared_ptr<FileCommand>> commands_;
};// 主函数:测试命令模式
int main() {CommandQueue queue;queue.AddCommand(std::make_shared<CreateFileCommand>("data.txt"));queue.AddCommand(std::make_shared<DeleteFileCommand>("temp.txt"));std::cout << "Processing commands..." << std::endl;queue.ProcessCommands();return 0;
}

四、实战场景:GUI 框架中的消息处理

4.1 模拟 Qt 信号槽机制

Qt 的信号槽机制是 C++ 中消息处理的经典实现,通过元对象系统实现组件间解耦。以下是简化的模拟实现:

①信号槽核心类

#include <iostream>
#include <vector>
#include <functional>// 信号类:支持绑定槽函数
template <typename... Args>
class Signal {
public:void Connect(std::function<void(Args...)> slot) {slots_.push_back(slot);}void Emit(Args... args) { // 发送消息for (const auto& slot : slots_) {slot(args...);}}private:std::vector<std::function<void(Args...)>> slots_;
};// 按钮类:发送点击消息
class GuiButton {
public:Signal<> clicked; // 无参数信号
};// 主函数:模拟GUI消息处理
int main() {GuiButton button;// 绑定槽函数:日志输出button.clicked.Connect([]() {std::cout << "Button clicked (via signal-slot)!" << std::endl;});// 触发信号:模拟按钮点击std::cout << "Simulating button click..." << std::endl;button.clicked.Emit();return 0;
}

五、高级主题:多线程消息队列

5.1 基于队列的异步消息处理

在多线程场景中,消息队列是实现线程间通信的常用方式。以下是一个简单的线程安全消息队列实现:

①线程安全队列类

#include <iostream>
#include <queue>template <typename T>
class NonThreadSafeQueue {
public:void Enqueue(T message) {queue_.push(std::move(message));}T Dequeue() {T message = queue_.front();queue_.pop();return message;}bool Empty() {return queue_.empty();}private:std::queue<T> queue_;
};// 消息类型定义
struct Message {int type;std::string data;
};// 生产者线程(非线程安全,仅演示逻辑)
void Producer(NonThreadSafeQueue<Message>& queue) {Message msg = {1, "Hello, message queue!"};queue.Enqueue(msg);std::cout << "Producer sent message: " << msg.data << std::endl;
}// 消费者线程(非线程安全,仅演示逻辑)
void Consumer(NonThreadSafeQueue<Message>& queue) {while (!queue.Empty()) {Message msg = queue.Dequeue();std::cout << "Consumer received message: " << msg.data << std::endl;}
}int main() {NonThreadSafeQueue<Message> queue;Producer(queue);Consumer(queue);return 0;
}

六、消息处理的最佳实践

6.1 解耦优先

  • 使用抽象接口(如观察者模式中的ButtonObserver)隔离发送者与接收者。
  • 避免硬编码依赖,通过工厂模式或依赖注入创建消息处理器。

6.2 线程安全

  • 多线程环境中,对共享消息队列加锁(如std::mutex)或使用无锁队列。
  • 消息对象设计为不可变或线程安全,避免竞态条件。

6.3 错误处理

为消息处理函数添加异常捕获,避免未处理异常导致程序崩溃。 

void OnButtonClick() {try {// 消息处理逻辑} catch (const std::exception& e) {std::cerr << "Message handling error: " << e.what() << std::endl;}
}

6.4 性能优化

  • 批量处理消息(如命令模式中的ProcessCommands())减少函数调用开销。
  • 使用智能指针(如std::shared_ptr)管理消息对象,避免内存泄漏。

七、总结

模式 / 场景核心机制适用场景
观察者模式主题 - 观察者订阅关系GUI 事件、状态变更通知
命令模式消息封装为可执行对象撤销操作、异步任务队列
信号槽机制动态绑定消息处理器Qt 等 GUI 框架
多线程队列线程安全的消息传递通道跨线程通信、异步任务处理

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

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

相关文章

【统计方法】交叉验证:Resampling, nested 交叉验证等策略 【含R语言】

Resampling (重采样方法) 重采样方法是从训练数据中反复抽取样本&#xff0c;并在每个&#xff08;重新&#xff09;样本上重新调整模型&#xff0c;以获得关于拟合模型的附加信息的技术。 两种主要的重采样方法 Cross-Validation (CV) 交叉验证 &#xff1a; 用于估计测试误…

常见的 CSS 知识点整理

1. 盒模型&#xff08;Box Model&#xff09;是什么&#xff1f;标准盒模型和 IE 盒模型的区别&#xff1f; 答案&#xff1a; CSS 盒模型将元素视为一个盒子&#xff0c;由内容&#xff08;content&#xff09;、内边距&#xff08;padding&#xff09;、边框&#xff08;bor…

Educational Codeforces Round 178 div2(题解ABCDE)

A. Three Decks #1.由于最后三个数会相等&#xff0c;提前算出来和&#xff0c;%3判断&#xff0c;再判前两个数是否大于 #include<iostream> #include<vector> #include<stdio.h> #include<map> #include<string> #include<algorithm> #…

如何创建一个导入模板?全流程图文解析

先去找到系统内可以上传东西的按钮 把你的模板上传上去,找到对应的fileName 图里的文字写错了,是复制粘贴"filePath"到URL才能下载

通信原理第七版与第六版区别附pdf

介绍 我用夸克网盘分享了「通信原理 第7版》樊昌信」&#xff0c;链接&#xff1a;https://pan.quark.cn/s/be7c5af4cdce 《通信原理&#xff08;第7版&#xff09;》是在第6版的基础上&#xff0c;为了适应当前通信技术发展和教学需求&#xff0c;并吸取了数十所院校教师的反…

Mysql唯一性约束

唯一性约束&#xff08;Unique Constraint&#xff09;是数据库设计中用于保证表中某一列或多列组合的值具有唯一性的一种规则。它可以防止在指定列中插入重复的数据&#xff0c;有助于维护数据的完整性和准确性。下面从几个方面为你详细解释 作用 确保数据准确性&#xff1a…

测试基础笔记第十六天

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、UI自动化介绍1.认识UI自动化测试2.实施UI自动化测试前置条件3.UI自动化测试执行时机4.UI自动化测试核心作用和劣势 二、认识Web自动化测试工具-Selenium021.Sel…

PaddleX的安装

参考&#xff1a;安装PaddlePaddle - PaddleX 文档 1、安装PaddlePaddle 查看 docker 版本 docker --version 若您通过 Docker 安装&#xff0c;请参考下述命令&#xff0c;使用飞桨框架官方 Docker 镜像&#xff0c;创建一个名为 paddlex 的容器&#xff0c;并将当前工作目…

长效住宅IP是什么?如何获取长效住宅IP?

在当今的互联网世界里&#xff0c;IP地址作为连接用户与网站之间的桥梁&#xff0c;其重要性不言而喻。对于跨境电商、社交媒体运营以及数据采集等领域的专业人士而言&#xff0c;普通的IP地址已无法满足日益复杂的需求。他们更需要一种稳定、安全且持久的长效住宅IP来完成各类…

02 业务流程架构

业务流程架构提供了自上而下的组织鸟瞰图&#xff0c;是业务流程的全景图。根据所采用的方法不同&#xff0c;有时被称为流程全景图或高层级流程图&#xff0c;提供了业务运营中所有业务流程的整体视图。 这样有助于理解企业内部各个业务流程之间的相互关系以及它们如何共同工…

jenkins slave节点打包报错Failed to create a temp file on

jenkins slave节点打包报错 一、报错信息 FATAL: Unable to produce a script file Also: hudson.remoting.Channel$CallSiteStackTrace: Remote call to slave-83at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1784)at hudson.remoting.UserRequest$…

什么是 Swagger 以及如何在 Spring Boot 中实现 Swagger:配置与实践指南

在现代 RESTful API 开发中&#xff0c;Swagger 是一种广泛使用的工具&#xff0c;用于生成、描述和可视化 API 文档。它极大地简化了 API 的开发、测试和维护过程。结合 Spring Boot&#xff0c;Swagger 可以快速集成到项目中&#xff0c;生成交互式 API 文档&#xff0c;方便…

Xilinx FPGA支持的FLASH型号汇总

以博主这些年的FPGA开发使用经验来看&#xff0c;FPGA开发的主流还是以Xilinx FPGA为主&#xff0c;贸易战关税战打了这么多年&#xff0c;我们做研发的也不可避免的要涉及一些国产替代的工作&#xff1b;这里把Xilinx FPGA官方支持的各类&#xff08;国产和非国产&#xff09;…

第3讲:ggplot2完美入门与美化细节打磨——从基础绘制到专业级润色

目录 1. 为什么选择ggplot2? 2. 快速了解ggplot2绘图核心逻辑 3. 基础绘图示范:柱状图、折线图、散点图 (1)简单柱状图 (2)折线图示范 (3)高级散点图 + 拟合线 4. 精细美化:细节打磨决定专业感 5. 推荐的美化小插件(可选进阶) 6. 小练习:快速上手一幅美化…

Vue3 上传后的文件智能预览(实战体会)

目录 前言1. Demo12. Demo2 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 爬虫神器&#xff0c;无代码爬取&#xff0c;就来&#xff1a;bright.cn 此处的基本知识涉及较少&#xff0c;主要以Demo的形式供大…

transformer-实现单层Decoder 层

Decoder Layer 论文地址 https://arxiv.org/pdf/1706.03762 解码器层结构 Transformer解码器层由三种核心组件构成&#xff1a; Masked多头自注意力&#xff1a;关注解码器序列当前位置之前的上下文&#xff08;因果掩码&#xff09; Encoder-Decoder多头注意力&#xff1a;关…

设计模式每日硬核训练 Day 16:责任链模式(Chain of Responsibility Pattern)完整讲解与实战应用

&#x1f504; 回顾 Day 15&#xff1a;享元模式小结 在 Day 15 中&#xff0c;我们学习了享元模式&#xff08;Flyweight Pattern&#xff09;&#xff1a; 通过共享对象&#xff0c;分离内部状态与外部状态&#xff0c;大量减少内存开销。适用于字符渲染、游戏场景、图标缓…

大数据开发环境的安装,配置(Hadoop)

1. 三台linux服务器的安装 1. 安装VMware VMware虚拟机软件是一个“虚拟PC”软件&#xff0c;它使你可以在一台机器上同时运行二个或更多Windows、DOS、LINUX系统。与“多启动”系统相比&#xff0c;VMWare采用了完全不同的概念。 我们可以通过VMware来安装我们的linux虚拟机…

多模态大语言模型arxiv论文略读(四十九)

When Do We Not Need Larger Vision Models? ➡️ 论文标题&#xff1a;When Do We Not Need Larger Vision Models? ➡️ 论文作者&#xff1a;Baifeng Shi, Ziyang Wu, Maolin Mao, Xin Wang, Trevor Darrell ➡️ 研究机构: UC Berkeley、Microsoft Research ➡️ 问题背…

【深度学习与大模型基础】第14章-分类任务与经典分类算法

Part 1&#xff1a;什么是分类任务&#xff1f; 1.1 分类就是“贴标签” 想象你有一堆水果&#xff0c;有苹果&#x1f34e;、橘子&#x1f34a;、香蕉&#x1f34c;&#xff0c;你的任务是让机器学会自动判断一个新水果属于哪一类——这就是分类&#xff08;Classification&…