C++如何实现观察者设计模式?C++代码解耦实战【设计模式】

发布时间 - 2025-12-25 00:00:00    点击率:
观察者模式在C++中通过抽象基类解耦Subject与Observer,用std::vector+weak_ptr管理观察者并自动清理,模板化SubjectBase提升复用性,具体类仅需继承并调用notify(),新增观察者零侵入。

观察者模式在C++中核心是解耦“被观察者”(Subject)和“观察者”(Observer),让两者只依赖抽象,不依赖具体实现。关键在于用抽象类定义接口、用容器管理观察者、用虚函数触发通知——不用信号槽、不依赖第三方库,纯标准C++就能落地。

定义抽象观察者和被观察者接口

先写两个纯虚基类:Observer 声明 update() 接口,Subject 声明 attach()/detach()/notify() 接口。所有具体类都继承它们,这样新增观察者或被观察者时,原有代码完全不用改。

注意:Observer 的 update() 通常接收 const Subject& 或 shared_ptr,避免拷贝、防止误修改;Subject 内部用 std::vector<:weak_ptr>> 存观察者,避免循环引用导致内存泄漏。

实现可复用的 Subject 基类模板

把通用逻辑抽成模板,减少重复代码。例如:

// 模板化 Subject 基类,自动管理 weak_ptr 观察者
template
class SubjectBase {
protected:
  std::vector<:weak_ptr>> observers_;
public:
  void attach(std::shared_ptr obs) {
    observers_.push_back(obs);
  }
  void notify() const {
    for (auto it = observers_.begin(); it != observers_.end();) {
      if (auto obs = it->lock()) {
        obs->update(*this);
        ++it;
      } else {
        it = observers_.erase(it); // 自动清理已销毁的观察者
      }
    }
  }
};

具体业务类按需继承并触发通知

比如一个温度传感器类:

class TemperatureSensor : public SubjectBase {
private:
  double temperature_ = 0.0;
public:
  void setTemperature(double t) {
    temperature_ = t;
    notify(); // 数据一变就广播,不关心谁在监听
  }
  double getTemperature() const { return temperature_; }
};

再写具体观察者,比如控制台打印器和日志记录器,都只实现自己的 update(),互不影响:

  • ConsoleDisplay::update() —— printf 当前温度
  • Logger::update() —— 写入文件或发网络请求

使用时只需组合,不修改已有类

main() 里创建对象、建立关系即可:

int main() {
  auto sensor = std::make_shared();
  auto display = std::make_shared();
  auto logger = std::make_shared();

  sensor->attach(display);
  sensor->attach(logger);

  sensor->setTemperature(25.6); // 自动触发 display 和 logger
  sensor->setTemperature(26.1); // 同样自动通知
}

以后加新功能(比如发邮件告警),只要写个 EmailAlert 类继承 Observer,实现 update(),再 attach 进去——零侵入、无编译依赖、职责清晰。

基本上就这些。不复杂但容易忽略 weak_ptr 清理、const 正确性、以及模板接口的泛化粒度。写熟了,一个项目里几十个松耦合的通知场景,都能靠这几行基类搞定。


# ai  # c++  # oled  # red  # if  # for  # printf  # const  # auto  # int  # double  # void  # 循环  # 继承  # 虚函数  # 接口  # 类模板  # class  # public  # private  # protected  # 对象  # this  # display  # 传感器  # 自己的  # 复用  # 不依赖  # 记录器  # 就能  # 都能  # 已有  # 只需  # 第三方  # 谁在 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  javascript中对象的定义、使用以及对象和原型链操作小结  Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧  Laravel怎么解决跨域问题_Laravel配置CORS跨域访问  rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted  非常酷的网站设计制作软件,酷培ai教育官方网站?  Midjourney怎样加参数调细节_Midjourney参数调整技巧【指南】  Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】  php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】  laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法  Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程  Thinkphp 中 distinct 的用法解析  JavaScript如何实现音频处理_Web Audio API如何工作?  Gemini手机端怎么发图片_Gemini手机端发图方法【步骤】  悟空识字如何进行跟读录音_悟空识字开启麦克风权限与录音  网站建设保证美观性,需要考虑的几点问题!  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  Android实现代码画虚线边框背景效果  重庆市网站制作公司,重庆招聘网站哪个好?  美食网站链接制作教程视频,哪个教做美食的网站比较专业点?  详解Android图表 MPAndroidChart折线图  如何在景安服务器上快速搭建个人网站?  如何用已有域名快速搭建网站?  JS碰撞运动实现方法详解  LinuxCD持续部署教程_自动发布与回滚机制  高防服务器如何保障网站安全无虞?  WordPress 子目录安装中正确处理脚本路径的完整指南  Laravel路由怎么定义_Laravel核心路由系统完全入门指南  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  Laravel如何使用withoutEvents方法临时禁用模型事件  UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】  mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?  浅谈javascript alert和confirm的美化  如何快速上传建站程序避免常见错误?  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  如何在万网主机上快速搭建网站?  Laravel如何使用Livewire构建动态组件?(入门代码)  焦点电影公司作品,电影焦点结局是什么?  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  如何在腾讯云服务器快速搭建个人网站?  如何快速搭建高效服务器建站系统?  如何彻底删除建站之星生成的Banner?  Laravel如何使用Vite进行前端资源打包?(配置示例)  瓜子二手车官方网站在线入口 瓜子二手车网页版官网通道入口  C++用Dijkstra(迪杰斯特拉)算法求最短路径  Laravel定时任务怎么设置_Laravel Crontab调度器配置  零服务器AI建站解决方案:快速部署与云端平台低成本实践  Python正则表达式进阶教程_复杂匹配与分组替换解析  Laravel Session怎么存储_Laravel Session驱动配置详解  Laravel如何处理文件下载请求?(Response示例)