首页 > 编程语言 >C++ 观察者模式实现

C++ 观察者模式实现

时间:2023-11-18 16:44:27浏览次数:37  
标签:主体 void 观察者 模式 Listener OnNotified vector C++

观察者模式

主体(被观察者)通知一个或多个观察者状态改变/数据更新/事件发生。

描述

C++ 实现观察者模式有几个要点:

  1. 观察者都有一个共同的抽象基类 Listener,定义了一个纯虚接口 OnNotified(),主体调用该接口通知观察者
  2. 每个观察者 ConcreteListener 继承自抽象基类 Listener,并实现 OnNotified() 方法
  3. 主体提供了注册 Listener 的方法 RegisterListener(Listener&),内部通过 vector 维护 listener 列表;当主体需要通知观察者时,遍历观察者列表,对每个观察者调用其 OnNotified() 方法。此处用了面向对象中的多态,即 vector 中保存的是各个 Listener 的指针或引用,主体只依赖 Listener 的抽象接口,无需关心观察者的具体类型。因为 vector 不能直接保存引用,可以使用指针或者 std::reference_wrapper<Listner>
  4. 主体也可以根据需要,提供 UnregisterListener 方法,观察者也可能需要保存主体的指针或引用,用于之后的 Unregister。

示例代码

#include <functional>
#include <vector>

class Listener {
 public:
  virtual ~Listener() = default;
  virtual void OnNotified() = 0;
  // 如果需要传递数据,可以在 OnNotified 接口中增加参数
  // virtual void OnNotified(const Data&) = 0;
};

class ConcreteListener : public Listener {
 public:
  void OnNotified() override {}
};

class Subject {
 public:
  void RegisterListener(Listener& o) {
    listeners_.push_back(o);
  }

 private:
  void NotifyListeners() {
    for (Listener& o : listeners_) {
      o.OnNotified();
    }
  }

  // 注意:vector 不能停直接保存引用,可以用 reference_wrapper
  std::vector<std::reference_wrapper<Listener>> listeners_;
};

传递数据的两种机制:Push 和 Pull

注意:在这个例子中,主体只是通知观察者,如果需要传递信息,有两种做法:

  • Push 推:直接在 OnNotified() 函数中增加参数,如 OnNotified(const Data&)。但是不同的观察者可能需要 Data 中的不同数据
  • Pull 拉:OnNotified() 不带参数,只负责通知变化,主体提供一组额外的 Getter 方法,当观察者收到通知时,根据自身需要,调用不同的 Getter 方法获取特定数据。

这两种方法都可以,实际项目中 Push 的方式更常见。

观察者模式的好处

观察者模式是 SOLID 原则中,遵循 “OCP 开放关闭原则” 的典型例子:

  • 对扩展开放:新的观察者只需要实现 ListenerOnNotified() 接口,并向主体注册即可
  • 对修改关闭:现有代码(主体的代码、其他观察者的代码)不需要修改

观察者和主体是解耦的:

  • 主体不了解观察者的细节,只知道观察者实现了 OnNotified() 接口
  • 观察者对主体也所知甚少,只知道主体提供了 RegisterListener(Listener& l) 方法,并通过 ListenerOnNotified() 方法通知观察者。

标签:主体,void,观察者,模式,Listener,OnNotified,vector,C++
From: https://www.cnblogs.com/tengzijian/p/17840711.html

相关文章

  • PVE 下虚拟机 Ubuntu 无法进入恢复模式的解决方案——提取原有系统文件
    问题说明某天重启虚拟机Ubuntu,发现虚拟机只有容器IP,桥接的接口在虚拟机显示状态为DOWN:想重启进入恢复模式,却发现恢复模式一直花屏,无法使用:没有办法了,只能想办法提取原有系统内原有文件。解决方案定位虚拟机编号:找到虚拟机主硬盘:SSH登录宿主机,执行以下命令ls-al......
  • Vue 设置为history模式之后,刷新页面报404错误的解决办法
    网上搜索出现很多修改前端或后端的方法试了都不行,后来在IIS中添加URL重写规则就解决了(如果没有Url重写模块,需要下载安装:rewrite_amd64_zh-CN.msi),设置重写之后会在网站前端根目录下生成一个web.config文件。所以如果嫌配置url重写麻烦的话,直接把这个web.config文件放置到自己网站......
  • C/C++ 运用VMI接口查询系统信息
    WindowsManagementInstrumentation(WMI)是一种用于管理和监视Windows操作系统的框架。它为开发人员、系统管理员和自动化工具提供了一种标准的接口,通过这个接口,可以获取有关计算机系统硬件、操作系统和应用程序的信息,以及对系统进行管理和控制的能力。WMI允许通过编程方式查询系......
  • L1-6 吉老师的回归 (15 分)(C/C++)
    输入样例1:51L1-1isaqiandaoproblem.L1-2isso...easy.L1-3isEasy.L1-4isqianDao.Wow,suchL1-5,soeasy.输出样例1:L1-4isqianDao.输入样例2:54L1-1isa-qiandaoproblem.L1-2issoeasy.L1-3isEasy.L1-4isqianDao.Wow,suchL1-5,so!!easy.输出样例......
  • Activiti工作流学习笔记(四)——工作流引擎中责任链模式的建立与应用原理
    原创/朱季谦本文需要一定责任链模式的基础与Activiti工作流知识,主要分成三部分讲解:一、简单理解责任链模式概念二、Activiti工作流里责任链模式的建立三、Activiti工作流里责任链模式的应用一、简单理解责任链模式概念网上关于责任链模式的介绍很多,菜鸟教程上是这样说的:责任链模式(C......
  • 创建顺序表(C++)
    include<stdio.h>defineMaxSize10 //定义最大长度//创建顺序表typedefstruct{intdata[MaxSize]; //创建数组data用来储存数据元素,并将data的长度设置为MaxSizeintlength; //顺序表的当前长度}SqList;//初始化顺序表voidInitList(SqList&L){for(inti=0;i<......
  • c++日志库-log4cplus
    《log4cplus日志库》1.Preface  log4cplus是一款开源的c++日志库,具有线程安全,灵活,以及多粒度控制的特点;log4cplus可以将日志按照优先级进行划分,使其可以面向程序的调试,运行,测试,后期维护等软件全生命周期;可以通过配置,选择将日志输出到屏幕,文件,NTeventlog,甚至是远程服务器......
  • 5 步在 Ubuntu22 上使用 C++20
    1.安装build-essentialsudoaptinstallbuild-essential安装完检查/usr/bin/下是否有gcc,g++,gcc-11,g++11.2.添加ppa源sudoadd-apt-repositoryppa:ubuntu-toolchain-r/test3.安装gcc-13和g++-13sudoapt-getinstallgcc-13sudoapt-getinstallg++-......
  • 最有效率的资金模式
    我在想最有效率的资金模式是什么?就是做股票的主升浪,如何做?1.跟踪市场热点。2.合适的价格介入,想清楚安全边际,盈亏比。(股票的合理价格作预估,目前处于什么水平)3.切忌在很热的时候买,风险较高。4.平时做好功课,选择一些股票列入股票池观察,当有异动出现,第一时间买入。5.根据当时的市......
  • 软件设计实验12:外观模式
    实验12:外观模式本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:1、理解外观模式的动机,掌握该模式的结构;2、能够利用外观模式解决实际问题。 [实验任务一]:计算机开启在计算机主机(Mainframe)中,只需要按下主机的开机按钮(on()),即可调用其他硬件设备和软件的启动方法......