当前位置: 首页 > news >正文

使用单例模式+观察者模式实现参数配置实时更新

使用vector存储观察者列表

#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>// 配置参数结构体
struct MyConfigStruct {int parameter1;std::string parameter2;
};class Config {
public:using Observer = std::function<void(const MyConfigStruct&)>;static Config& getInstance() {static Config instance;return instance;}// 注册观察者void registerObserver(Observer observer) {observers_.push_back(observer);}// 移除观察者void removeObserver(Observer observer) {observers_.erase(std::remove_if(observers_.begin(), observers_.end(),[observer](const Observer& o) {return o.target_type() == observer.target_type();}), observers_.end());}/*void removeObserver(Observer observer) {auto it = std::find_if(observers_.begin(), observers_.end(),[observer](const Observer& o) {return &o == &observer;});if (it != observers_.end()) {observers_.erase(it);}}*/// Setter方法用于修改配置参数的值void setParameters(const MyConfigStruct& newParameters) {parameters_ = newParameters;notifyObservers();}private:Config() {// 初始化配置参数parameters_ = { 0, "" };}// 配置参数MyConfigStruct parameters_;// 观察者集合std::vector<Observer> observers_;// 通知观察者void notifyObservers() {for (const auto& observer : observers_) {observer(parameters_);}}
};// 模块A作为观察者,处理参数变化的通知
class ModuleA {
public:void handleConfigUpdate(const MyConfigStruct& config) {std::cout << "Module A: Parameter 1 = " << config.parameter1 << ", Parameter 2 = " << config.parameter2 << std::endl;}
};// 模块B作为观察者,处理参数变化的通知
class ModuleB {
public:void handleConfigUpdate(const MyConfigStruct& config) {std::cout << "Module B: Parameter 1 = " << config.parameter1 << ", Parameter 2 = " << config.parameter2 << std::endl;}
};int main() {// 创建配置实例和模块实例Config& config = Config::getInstance();ModuleA moduleA;ModuleB moduleB;// 注册观察者config.registerObserver([&moduleA](const MyConfigStruct& config) {moduleA.handleConfigUpdate(config);});config.registerObserver([&moduleB](const MyConfigStruct& config) {moduleB.handleConfigUpdate(config);});// 更新配置参数MyConfigStruct newParameters{ 42, "Hello World" };config.setParameters(newParameters);// 移除观察者config.removeObserver([&moduleA](const MyConfigStruct& config) {moduleA.handleConfigUpdate(config);});// 再次更新配置参数MyConfigStruct newParameters2{ 100, "Goodbye" };config.setParameters(newParameters2);return 0;
}

输出结果

Module A: Parameter 1 = 42, Parameter 2 = Hello World
Module B: Parameter 1 = 42, Parameter 2 = Hello World
Module A: Parameter 1 = 100, Parameter 2 = Goodbye
Module B: Parameter 1 = 100, Parameter 2 = Goodbye

removeObserver 方法中,我们使用了 std::remove_if 来查找并移除与指定观察者对象类型相同的观察者。通过比较 o.target_type()observer.target_type() 可以判断两个观察者对象的类型是否相同。
在 C++ 中,std::function 是一个通用的函数封装器,可以包装任意可调用对象(如函数指针、函数对象、Lambda 表达式等)。为了允许运行时检查 std::function 所包装的具体函数对象类型,C++ 提供了 target_type() 成员函数来获取存储的函数对象类型信息。

在上述代码中,我们使用 o.target_type()observer.target_type() 来比较两个观察者对象的函数对象类型是否相同。这样做是为了确保移除与指定观察者对象类型相同的观察者。

请注意,target_type() 返回的是 std::type_info 对象的指针,而不是直接的类型。因此,我们使用 == 运算符来比较两个 std::type_info 对象的指针是否相等,以判断两个观察者对象的函数对象类型是否相同。

使用set存储观察者列表

#include <iostream>
#include <set>
#include <functional>// 配置参数结构体
struct MyConfigStruct {int parameter1;std::string parameter2;
};class Config {
public:using Observer = std::function<void(const MyConfigStruct&)>;static Config& getInstance() {static Config instance;return instance;}// 注册观察者void registerObserver(Observer observer) {observers_.insert(observer);}// 移除观察者void removeObserver(Observer observer) {observers_.erase(observer);}// Setter方法用于修改配置参数的值void setParameters(const MyConfigStruct& newParameters) {parameters_ = newParameters;notifyObservers();}private:Config() {// 初始化配置参数parameters_ = { 0, "" };}// 配置参数MyConfigStruct parameters_;// 比较函数对象,用于在集合中排序观察者struct ObserverComparator {bool operator()(const Observer& lhs, const Observer& rhs) const {// 在这里实现你需要的比较逻辑// 这里简单地使用内存地址进行比较return &lhs < &rhs;}};// 观察者集合std::set<Observer, ObserverComparator> observers_;// 通知观察者void notifyObservers() {for (const auto& observer : observers_) {observer(parameters_);}}
};// 模块A作为观察者,处理参数变化的通知
class ModuleA {
public:void handleConfigUpdate(const MyConfigStruct& config) {std::cout << "Module A: Parameter 1 = " << config.parameter1 << ", Parameter 2 = " << config.parameter2 << std::endl;}
};// 模块B作为观察者,处理参数变化的通知
class ModuleB {
public:void handleConfigUpdate(const MyConfigStruct& config) {std::cout << "Module B: Parameter 1 = " << config.parameter1 << ", Parameter 2 = " << config.parameter2 << std::endl;}
};int main() {// 创建配置实例和模块实例Config& config = Config::getInstance();ModuleA moduleA;ModuleB moduleB;// 注册观察者config.registerObserver([&moduleA](const MyConfigStruct& config) {moduleA.handleConfigUpdate(config);});config.registerObserver([&moduleB](const MyConfigStruct& config) {moduleB.handleConfigUpdate(config);});// 更新配置参数MyConfigStruct newParameters{ 42, "Hello World" };config.setParameters(newParameters);// 移除观察者config.removeObserver([&moduleA](const MyConfigStruct& config) {moduleA.handleConfigUpdate(config);});// 再次更新配置参数MyConfigStruct newParameters2{ 100, "Goodbye" };config.setParameters(newParameters2);return 0;
}

同样的输出结果

Module A: Parameter 1 = 42, Parameter 2 = Hello World
Module B: Parameter 1 = 42, Parameter 2 = Hello World
Module A: Parameter 1 = 100, Parameter 2 = Goodbye
Module B: Parameter 1 = 100, Parameter 2 = Goodbye

在上述代码中,ObserverComparator 是一个用于比较观察者对象的比较器结构体。它实现了一个 operator() 函数,该函数接受两个观察者对象作为参数,并返回一个布尔值来表示它们的相对顺序。

在这个比较器中,我们简单地使用观察者对象的内存地址进行比较。如果 &lhs 小于 &rhs,则认为 lhs 在集合中应该排在 rhs 的前面,返回 true。否则,返回 false

通过使用自定义的比较器,我们可以在 std::set 中根据指定的比较逻辑对观察者进行排序。这样做可以确保观察者在集合中以特定的顺序存储,并且在通知观察者时按照指定的顺序进行遍历。

需要注意的是,由于比较的是观察者对象的地址而不是函数对象本身,因此在使用这种比较器时需要小心。确保观察者对象的生命周期足够长,以便比较其地址的有效性。

相关文章:

使用单例模式+观察者模式实现参数配置实时更新

使用vector存储观察者列表 #include <iostream> #include <vector> #include <functional> #include <algorithm>// 配置参数结构体 struct MyConfigStruct {int parameter1;std::string parameter2; };class Config { public:using Observer std::f…...

区块链实验室(28) - 拜占庭节点劫持区块链仿真

在以前的FISCO环境中仿真拜占庭节点攻击区块链网络。该环境共有100个节点&#xff0c;采用PBFT作为共识机制&#xff0c;节点编号分别为&#xff1a;Node0&#xff0c;Node&#xff0c;… &#xff0c;Node99。这100个节点的前2010区块完全相同&#xff0c;自区块2011开始分叉。…...

聊聊AsyncHttpClient的ChannelPool

序 本文主要研究一下AsyncHttpClient的ChannelPool ChannelPool org/asynchttpclient/channel/ChannelPool.java public interface ChannelPool {/*** Add a channel to the pool** param channel an I/O channel* param partitionKey a key used to retrieve the cac…...

[MySQL] MySQL复合查询(多表查询、子查询)

前面我们学习了MySQL简单的单表查询。但是我们发现&#xff0c;在很多情况下单表查询并不能很好的满足我们的查询需求。本篇文章会重点讲解MySQL中的多表查询、子查询和一些复杂查询。希望本篇文章会对你有所帮助。 文章目录 一、基本查询回顾 二、多表查询 2、1 笛卡尔积 2、2…...

[架构之路-256]:目标系统 - 设计方法 - 软件工程 - 软件设计 - 架构设计 - 软件系统不同层次的复用与软件系统向越来越复杂的方向聚合

目录 前言&#xff1a; 一、CPU寄存器级的复用&#xff1a;CPU寄存器 二、指令级复用&#xff1a;二进制指令 三、过程级复用&#xff1a;汇编语言 四、函数级复用&#xff1a;C语言 五、对象级复用&#xff1a;C, Java, Python 六、组件级复用 七、服务级复用 八、微…...

C++初学教程三

目录 一、运算符 一、自增自减运算符 二、位运算符 三、关系运算符...

雷达点云数据.pcd格式转.bin格式

雷达点云数据.pcd格式转.bin格式 注意&#xff0c;方法1原则上可行&#xff0c;但是本人没整好pypcd的环境 方法2是绝对可以的。 方法1 1 源码如下&#xff1a; def pcb2bin1(): # save as bin formatimport os# import pypcdfrom pypcd import pypcdimport numpy as np…...

Fiddler抓包测试

模拟弱网测试 操作&#xff1a;一、Rules - Customize Rules &#xff08;快捷键CtrlR&#xff09;弹出编辑器 二、接着CtrlF查找m_SimulateModem标志位 三、默认上传300ms&#xff0c;下载150ms 四、更改后&#xff0c;继续Rules - Performances - Simulate Modem Speeds勾上 …...

视频处理关键知识

1 引言 视频技术发展到现在已经有100多年的历史&#xff0c;虽然比照相技术历史时间短&#xff0c;但在过去很长一段时间之内都是最重要的媒体。由于互联网在新世纪的崛起&#xff0c;使得传统的媒体技术有了更好的发展平台&#xff0c;应运而生了新的多媒体技术。而多媒体技术…...

LeetCode435. Non-overlapping Intervals

文章目录 一、题目二、题解 一、题目 Given an array of intervals intervals where intervals[i] [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping. Example 1: Input: intervals [[1,2]…...

ffmpeg 实现多视频轨录制到同一个文件

引言 在视频录制中&#xff0c;有时会碰到这样一个需求&#xff0c;将不同摄像头的画面写入到一个视频文件&#xff0c;这个叫法很多&#xff0c;有的厂家叫合流模式&#xff0c;有的叫多画面多流模式。无论如何&#xff0c;它们的实质都是在一个视频文件上实现多路不同分辨率视…...

vue3中子组件调用父组件的方法

<script lang"ts" setup>前提 父组件&#xff1a; 子组件&#xff1a; const emit defineEmits([closeson]) 在子组件的方法中使用&#xff1a; emit(closeson)...

使用OkHttp上传本地图片及参数

下面以一个例子来讲解在项目中如何使用OKHttp来对本地图片做个最简单的上传功能&#xff0c;基本上无封装&#xff0c;只需要简单调用便可&#xff08;对于OKHttp的引入不再单独做介绍&#xff09;。 1&#xff1a;构建上传图片附带的参数&#xff08;params&#xff09; Map…...

无公网IP环境如何SSH远程连接Deepin操作系统

文章目录 前言1. 开启SSH服务2. Deppin安装Cpolar3. 配置ssh公网地址4. 公网远程SSH连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 前言 Deepin操作系统是一个基于Debian的Linux操作系统&#xff0c;专注于使用者对日常办公、学习、生活和娱乐的操作体验的极致&#xff0…...

不会代码(零基础)学语音开发(语音控制板载双继电器)

继电器的用途可广了&#xff0c;这个语音控制用处也特别广。继电器&#xff0c;它实际上是一种“自动开关”&#xff0c;用小电流去控制大电流运作&#xff0c;在电路中起着自动调节、安全保护、转换电路等作用。 在日常生活中&#xff0c;你插入汽车钥匙&#xff0c;车辆可以…...

在imx6ull中加入ov5640模块

本来觉得是一件很简单的事情但是走了很多的弯路&#xff0c;记录一下调试过程。 先使用正点原子提供的出厂内核把摄像头影像调试出来&#xff0c;然后cat /dev/video1&#xff0c;看一下video1牵扯到哪些模块&#xff0c;可以看到需要ov5640_camera.ko和 mx6s_capture.ko这两个…...

Kafka中的auto-offset-reset配置

Kafka这个服务在启动时会依赖于Zookeeper&#xff0c;Kafka相关的部分数据也会存储在Zookeeper中。如果kafka或者Zookeeper中存在脏数据的话&#xff08;即错误数据&#xff09;&#xff0c;这个时候虽然生产者可以正常生产消息&#xff0c;但是消费者会出现无法正常消费消息的…...

TCP/IP_整理起因

先分享一个初级的问题&#xff1b;有个客户现场&#xff0c;终端设备使用客户网络更新很慢&#xff0c;使用手机热点更新速度符合预期&#xff1b;网络部署情况如下&#xff1a; 前期花费了很大的精力进行问题排查对比&#xff0c;怀疑是客户网络问题&#xff08;其他的客户现…...

CG-0A 电子水尺水导电测量原理应用于道路积水监测

CG-0A 电子水尺水导电测量原理应用于道路积水监测产品概述 本产品是一种采用微处理器芯片为控制器&#xff0c;内置通讯电路的数字式水位传感器&#xff0c;具备高的可靠性及抗干扰性能。适用于江、河、湖、水库及蓄水池、水渠等处的水位测量使用。 本产品采用了生产工艺技术…...

openEuler JDK21 部署 Zookeeper 集群

zookeeper-jdk21 操作系统&#xff1a;openEuler JDK&#xff1a;21 主机名IP地址spark01192.168.171.101spark02192.168.171.102spark03192.168.171.103 安装 1. 升级内核和软件 yum -y update2. 安装常用软件 yum -y install gcc gcc-c autoconf automake cmake make \zl…...

3步快速修复Netgear路由器变砖的终极解决方案

3步快速修复Netgear路由器变砖的终极解决方案 【免费下载链接】nmrpflash Netgear Unbrick Utility 项目地址: https://gitcode.com/gh_mirrors/nmr/nmrpflash 路由器变砖是许多网络设备用户最头疼的问题之一&#xff0c;特别是当固件升级失败或意外断电导致设备无法启动…...

如何快速使用网站历史查看器:新手完整入门教程

如何快速使用网站历史查看器&#xff1a;新手完整入门教程 【免费下载链接】wayback-machine-webextension A web browser extension for Chrome, Firefox, Edge, and Safari 14. 项目地址: https://gitcode.com/gh_mirrors/wa/wayback-machine-webextension 你是否曾经…...

操作系统面试必考:银行家算法10问10答(含真题解析)

操作系统面试必考&#xff1a;银行家算法10问10答&#xff08;含真题解析&#xff09; 银行家算法作为操作系统中经典的死锁避免算法&#xff0c;几乎成为所有技术面试的必考题。无论是校招还是社招&#xff0c;面试官总喜欢用它来考察候选人对资源分配与系统安全的理解深度。本…...

MATLAB实战:用LQR控制算法让二级倒立摆稳如老狗(附完整代码)

MATLAB实战&#xff1a;用LQR控制算法驯服二级倒立摆 记得第一次在实验室见到二级倒立摆时&#xff0c;那两根倔强的摆杆就像喝醉的水手&#xff0c;稍有不慎就东倒西歪。当时我就想&#xff0c;要是能像马戏团驯兽师那样让它们乖乖立正该多好。今天&#xff0c;我们就用MATLAB…...

vLLM PD分离架构在昇腾910B上的性能实测:对比单卡部署,吞吐量到底提升了多少?

vLLM PD分离架构在昇腾910B上的性能突破&#xff1a;实测数据与技术解析 当大模型推理从实验室走向生产环境&#xff0c;吞吐量与延迟指标直接决定了商业可行性。传统同构部署方案中&#xff0c;Prefill&#xff08;首字生成&#xff09;与Decode&#xff08;后续生成&#xff…...

六自由度机械臂逆解入门:当你的机械手‘知道’位置,如何反推关节角度?

六自由度机械臂逆解入门&#xff1a;从末端位姿反推关节角度的实战指南 当你第一次让机械臂抓取桌上的水杯时&#xff0c;可能会遇到一个令人困惑的问题&#xff1a;明明知道杯子在三维空间中的精确位置和朝向&#xff0c;却不知道该如何设置六个关节的旋转角度。这就是逆运动学…...

为机械臂视觉抓取做准备:在Ubuntu 18.04上配置ROS+YOLOv5运行环境的完整避坑清单

为机械臂视觉抓取做准备&#xff1a;在Ubuntu 18.04上配置ROSYOLOv5运行环境的完整避坑清单 当机械臂遇上YOLOv5&#xff0c;视觉抓取的能力边界将被重新定义。但在这之前&#xff0c;开发者需要跨越环境配置的"死亡之谷"——特别是当Ubuntu 18.04、ROS Melodic和PyT…...

突破Unity游戏语言壁垒:XUnity Auto Translator的多维度解决方案

突破Unity游戏语言壁垒&#xff1a;XUnity Auto Translator的多维度解决方案 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 在全球化游戏市场中&#xff0c;语言差异已成为制约玩家体验的关键瓶颈。独立…...

别再只会用QProgressBar了!用QPainterPath绘制Qt自定义进度条的完整指南

用QPainterPath实现Qt动态进度条的终极艺术 当标准进度条无法满足现代UI设计需求时&#xff0c;Qt的绘图系统为我们打开了无限可能。想象一下&#xff1a;你的应用加载界面不是单调的横条&#xff0c;而是会呼吸的光环、跳动的粒子流或是随音乐律动的波形——这些令人眼前一亮的…...

Powershell创建ISO文件全攻略:从基础命令到高级参数详解

PowerShell创建ISO文件全攻略&#xff1a;从基础命令到高级参数详解 在数据迁移、软件分发或系统部署场景中&#xff0c;ISO映像文件因其通用性和完整性验证机制成为首选载体。传统方式依赖第三方工具的时代已经过去&#xff0c;Windows PowerShell作为系统级脚本环境&#xff…...