观察者模式

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

描述

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() 方法通知观察者。

C++ 观察者模式实现的更多相关文章

  1. 23种设计模式--观察者模式-Observer Pattern

    一.观察者模式的介绍      观察者模式从字面的意思上理解,肯定有两个对象一个是观察者,另外一个是被观察者,观察者模式就是当被观察者发生改变得时候发送通知给观察者,当然这个观察者可以是多个对象,在项 ...

  2. 谈谈JS的观察者模式(自定义事件)

    呼呼...前不久参加了一个笔试,里面有一到JS编程题,当时看着题目就蒙圈...后来研究了一下,原来就是所谓的观察者模式.就记下来...^_^ 题目 [附加题] 请实现下面的自定义事件 Event 对象 ...

  3. ObserverPattern(观察者模式)

    import java.util.ArrayList; import java.util.List; /** * 观察者模式 * @author TMAC-J * 牵一发而动全身来形容观察者模式在合适 ...

  4. java观察者模式

      像activeMQ等消息队列中,我们经常会使用发布订阅模式,但是你有没有想过,客户端时如何及时得到订阅的主题的信息?其实就里就用到了观察者模式.在软件系统中,当一个对象的行为依赖于另一个对象的状态 ...

  5. Backbone源码解析(六):观察者模式应用

    卤煮在大概一年前写过backbone的源码分析,里面讲的是对一些backbone框架的方法的讲解.这几天重新看了几遍backbone的源码,才发现之前对于它的理解不够深入,只关注了它的一些部分的细节和 ...

  6. PHP 高级编程(3/5) - 使用SPL(标准PHP库)实现观察者模式

    SPL(标准PHP库 - Standard PHP Library)是PHP5面向对象功能中重要的部分.原文解释是这样的“The Standard PHP Library (SPL) is a col ...

  7. 设计模式--观察者模式初探和java Observable模式

    初步认识观察者模式 观察者模式又称为发布/订阅(Publish/Subscribe)模式,因此我们可以用报纸期刊的订阅来形象的说明: 报社方负责出版报纸. 你订阅了该报社的报纸,那么只要报社发布了新报 ...

  8. 学C#之设计模式系列笔记(2)观察者模式

    一.借鉴说明 1.<Head First Design Patterns>(中文名<深入浅出设计模式>) 2.维基百科,观察者模式,https://zh.wikipedia.o ...

  9. PHP 观察者模式

    观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. [观察者模式中主要角色] 1.抽象主题(Subject)角色: 抽象主题提供了增加 ...

  10. GJM: 设计模式 - 观察者模式

    GJM : 观察者模式 视频地址: http://www.imooc.com/learn/415 本课程通过一个天气预报的发布和订阅案例,来讲解观察者模式在Java项目中的应用.主要包括观察者模式的结 ...

随机推荐

  1. Go接口 - 构建可扩展Go应用

    本文深入探讨了Go语言中接口的概念和实际应用场景.从基础知识如接口的定义和实现,到更复杂的实战应用如解耦与抽象.多态.错误处理.插件架构以及资源管理,文章通过丰富的代码示例和详细的解释,展示了Go接口 ...

  2. 如何将linux设置成网关

    如何将linux设置成网关 打开网关linux的端口转发功能:echo '1' > /proc/sys/net/ipv4/ip_forward 在VMWare中创建一个仅主机的内网: 进入本机配 ...

  3. 使用go语言开发hive导出工具

    前言 新版 hive 提供了 beeline 工具,可以执行SQL并导出数据,不过操作还是有点复杂的,团队里有些同学不会Linux的基本操作,所以我花了亿点点时间写了个交互式的命令行工具方便使用. 效 ...

  4. cannot import name '_BindParamClause' from 'sqlalchemy.sql.expression'

    python3.8 安装环境组件正常安装 运行 flask db init 报错 cannot import name '_BindParamClause' from 'sqlalchemy.sql. ...

  5. 不同角度理解线程的状态(操作系统 & Java API)

    3.12 五种状态 ( 操作系统 层面) 这是从 操作系统 层面来描述的 [初始状态]仅是在语言层面创建了线程对象,还未与操作系统线程关联 [可运行状态](就绪状态)指该线程已经被创建(与操作系统线程 ...

  6. C# 压缩PDF文件

    PDF 文件可以包含文本.图片及各种媒体元素,但如果文件太大则会影响传输效果同时也会占用过多磁盘空间.通过压缩PDF文件,能够有效减小文件大小,从而提高传输效率并节省存储空间.想要通过C#代码快速有效 ...

  7. python3使用pymsql操作mysql数据库

    操作系统 :Windows 10_x64 python版本 :3.9.2 pymysql版本: 1.0.2 MySQL版本: 5.7.38   之前写过一篇关于python操作mysql数据库的文章: ...

  8. .NET6中的await原理浅析

    前言 看过不少关于 await 的原理的文章,也知道背后是编译器给转成了状态机实现的,但是具体是怎么完成的,回调又是如何衔接的,一直都没有搞清楚,这次下定决心把源码自己跑了下,终于豁然开朗了 本文的演 ...

  9. H.264 和 H.265对比

    前言 H.264标准正式发布于2003年3月,距今已经20多年了,但它仍然是当下最流行的视频编解码标准. H.265正式发布于2013年4月.虽然H.265标准是围绕着H.264进行制定的,也保留了原 ...

  10. 如何从Webpack迁移到Vite

    本文将介绍如何将前端web应用程序从 Webpack 升级到 Vite. Vite 是最新的前端开发工具,其受欢迎程度和采用率都在大幅增长.可以查看下图中来自 npm trends 的下载. 推动这一 ...