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

观察者模式与发布订阅模式

前言

我的任督二脉终于被打通了,现在该你了

区别

观察者模式

  1. 就2个角色:观察者和被观察者(重要)
  2. 明确知道状态源,明确知道对方是谁
  3. 一对多关系

发布订阅模式

  1. 有3个角色:发布者,订阅者和发布订阅中心(重要)
  2. 发布者和订阅者不知对方存在
  3. 多对多关系

观察者模式

  1. 观察者盯着被观察者看
  2. 被观察者将有权限添加,删除和通知观察者(这是被观察者至少需要的三个基本方法)
  3. 只要被观察者 发动 通知观察者方法时,观察者列表里的所有观察者就可以接收到消息

(一)实现

1. 被观察者(有一个观察者列表,可以添加,移除和通知观察者)

class Subject {constructor(){// 定义一个观察者列表用来存放观察者们this.observerList = [];}// 添加观察者    addObserver(observer){this.observerList.push(observer);}// 移除观察者removeObserver(observer){this.observerList.filter(o => o.name !== observer.name)}// 通知观察者notifyObserver(message){// 我理解的 notified 是观察者自己定义的如何通知自己,// 每个观察者的notified内部实现可能是不一样的this.observerList.forEach(o => o.notified(message))}}

2. 观察者(可以申请加入被观察者的列表,自定义通知方法)

class Observer {constructor(name, subject){this.name = name;if(subject){// 如果构建时就有了被观察者(subject),// 则申请让被观察者将自己加入列表subject.addObserver(this)}}notified(message){// TODO 观察者拿到订阅到的消息后要做的事console.log(this.name, '拿到了消息',message)}}

3. 使用

// 生成一个被观察者const subject = new Subject();// 生成一个自带subject的观察者const A_observer = new Observer('A',subject);// 通知subject.notifyObserver('咳咳');
// A拿到了消息咳咳// 生成一个没有观察对象subject的观察者const B_observer = new Observer('B',null);// 申请观察subjectsubject.addObserver(B_observer);
// 移除// subject.removeObserver(A_observer);
// 通知subject.notifyObserver('哈哈哈')    
// A拿到了消息哈哈哈
// B拿到了消息哈哈哈
// 当然也可以写一个新的class Observer来实现不同的notified

参考https://juejin.cn/post/6978728619782701087

(二)升级版实现

1. 被观察者

class newSubject {constructor(){this.observerList = [];}// 移除观察者removeObserver(observer){this.observerList.filter(o => o.name !== observer.name)}
__________修改___________________________________________________________________// 添加观察者addObserver(name, func){this.observerList.push({ name:name, callback:func});}// 通知观察者notifyObserver(message){// 我理解的 notified 是观察者自己定义的一个回调函数,// 即被观察者(observer)给观察者(subject)一个notified函数,告诉subject有消息就用这个函数通知自己,// 每个观察者的notified内部实现可能是不一样的// this.observerList.forEach(o => o.notified(message))// 通过对象的解构赋值,这样就可以不用规定死observer内部通知方法的名称为notified,更加灵活this.observerList.forEach(({name,callback}) => callback(message))}
}

2. 使用

    const new_subject = new newSubject();//添加观察者C时,将new_subject的观察者列表修改为统一的 { name, callback } 格式new_subject.addObserver('C',(message)=>{// notifiedconsole.log('hello, C', message)})//通知new_subject.notify(‘升级啦’)//‘hello, C升级啦’

参考http://dennisgo.cn/Articles/DesignPatterns/PubSub.html

一旦调用了subject.notify , 所有列表内的观察者都会收到通知,而且收到的是同样的消息

发布订阅模式

  1. 如之前所说,发布订阅模式有3个角色,发布者,订阅者和发布订阅中心,
  2. 发布订阅核心是基于发布订阅中心来建立联系
  3. 发布者无需关心订阅者有哪些,订阅者也无需关心有哪些发布者,可以表达对一个或多个主题的兴趣,只接收感兴趣的消息

让我们来想象一下邮件系统,你可以作为订阅者订阅某个网站的通知,邮件系统在其中充当发布订阅中心的角色,而发布者则是你订阅的网站。

整个链路是从你的订阅开始,你的订阅动作是在某个你想订阅的网站填入自己的邮箱(在主题中添加订阅者列表),并在邮箱内记录这个网站信息(添加主题),后续当网站有内容更新时,邮件系统会及时接收到并向你发送邮件。
————————————————引用自掘金 https://juejin.cn/post/6978728619782701087

(一)实现

1. 发布订阅中心 (记住订阅是在为主题添加订阅者,发布是在执行订阅者的通知方法)

// 发布订阅中心
class PubSub {constructor() {this.sublist = {}; //为什么观察者模式要用数组,这里却要用对象?想想平时在设置变量时,一对多的关系一般用数组来表示,而多对多的关系一般都用//数组对象来表示是不是//订阅列表,每个主题对应对象中的一个数组,键为主题名,值为不同订阅者的通知方式(可以理解为该主题下的订阅者列表)//为每个主题添加了多个订阅者,存放在数组(订阅者列表)中/*** this.sublist = {*     theme1:[notify_1_1, notify_1_2], // notify_1_1订阅了theme1,notify_1_2订阅了theme1,*     theme2:[notify_1_1, notify_2_2], // notify_1_1订阅了theme2,notify_2_2订阅了theme2,*     ......* }* **/}// 订阅subscribe(theme, notify_fn) {// 如果this.sublist[theme]为null,先将其定义为数组, 有了主题后,直接push订阅者的通知方法即可(this.sublist[theme] || (this.sublist[theme] = [])).push(notify_fn);}// 发布publish(theme, ...args) {if(!this.sublist[theme]){// 如果该主题不存在通知方法(即订阅者)return;}// 发布某个主题时,该主题的所有订阅者都可以接到通知this.sublist[theme].map(notify_fn => notify_fn(args))}}

2. 使用

 const pubsub = new PubSub();// 订阅者function user1(content) {console.log('用户1订阅 ',content)}function user2(content) { console.log('用户2订阅 ',content)}function user3(content) {console.log('用户3订阅 ',content)}// 添加订阅pubsub.subscribe('theme1',(content)=>{// 以后如果发布订阅中心pubsub发布了theme1的内容,立即通知执行user1方法user1(content)})pubsub.subscribe('theme1',(content)=>{user2(content)})pubsub.subscribe('theme2',(content)=>{user3(content)})// 发布(发布即起到了通知的作用,只有发布订阅中心执行发布方法,订阅者才能收到消息,因为publish执行了notify_fn)pubsub.publish('theme1', '主题1内容');pubsub.publish('theme2', '主题2内容');// 结果// 用户1订阅 主题1内容// 用户2订阅 主题1内容// 用户3订阅 主题2内容

参考
https://extremej.itscoder.com/different_between_observe_and_publish/
http://dennisgo.cn/Articles/DesignPatterns/PubSub.html
https://juejin.cn/post/6844903842501378055
https://juejin.cn/post/6844903850105634824

实际场景

  1. Node.js中自带的EventEmiter模块
  2. Vue.js中数据响应式的实现
  3. watch、watcher、observe、observer、listen、listener、dispatch、trigger、emit、on、event、eventbus、EventEmitter这类单词出现的地方,很有可能是在使用观察者模式或发布订阅模式
  4. 例如on (subscribe),和 emit(publish)

总结

1. 角色对象

  • 观察者模式角色:观察者和被观察者
  • 发布订阅模式角色:发布者,订阅者和发布订阅中心

2. 实现

  • 观察者模式:
    • 被观察者(有一个观察者列表,可以添加,移除和通知观察者)
    • 观察者(可以申请加入被观察者的列表,自定义通知方法)
  • 发布订阅模式:
    • 发布订阅中心 (记住订阅是在为主题添加订阅者,发布是在执行订阅者的通知方法)

3. 特定消息接收

  • 发布订阅模式可以自定义需要接受的通知,定制主题
  • 观察者模式相当于是无差别广播,一旦调用了notify通知 , 所有列表内的观察者都会收到通知,而且收到的是同样的消息

4. 映射关系

  • 观察者模式:普遍一对多
  • 发布订阅模式:普遍多对多

5. 对象间关系

  • 观察者模式:明确知道状态源,双方直接联系
  • 发布订阅者模式:双方通过发布订阅中心关联

相关文章:

观察者模式与发布订阅模式

前言 我的任督二脉终于被打通了,现在该你了 区别 观察者模式 就2个角色:观察者和被观察者(重要)明确知道状态源,明确知道对方是谁一对多关系 发布订阅模式 有3个角色:发布者,订阅者和发布订阅…...

磨金石教育摄影技能干货分享|烟花三月下扬州,是时候安排了!

人间三月最柔情,杨柳依依水波横。三月的风将要吹来,春天的门正式打开。对中国人来说,古往今来,赏春最好的地方是江南。人人都说江南好,可是江南哪里好呢?古人在这方面早就给出了答案:故人西辞黄…...

Kafka 消费组位移

Kafka 消费组位移消费者 API命令行Kafka : 基于日志结构(log-based)的消息引擎 消费消息时,只是从磁盘文件上读取数据,不会删除消息数据位移数据能由消费者控制,能很容易修改位移的值,实现重复消费历史数据…...

Python|数学|贪心|数组|动态规划|单选记录:实现保留3位有效数字(四舍六入五成双规则)|用Python来创造一个提示用户输入数字的乘法表|最小路径和

1、实现保留3位有效数字(四舍六入五成双规则)(数学,算法) 贡献者:weixin_45782673 输入:1234 输出:1234 12 12.0 4 4.00 0.2 0.200 0.32 0.320 1.3 1.30 1.235 1.24 1.245 1.24 1.…...

【MySQL】MySQL的索引

目录 介绍 索引的分类 索引的操作-创建索引-单列索引-普通索引 格式 操作 索引的操作-创建索引-单列索引-唯一索引 索引的操作-创建索引-单列索引-主键索引 索引的操作-创建索引-组合索引 索引的操作-全文索引 索引的操作-空间索引 索引的验证 索引的特点 介绍…...

弱监督实例分割 Box-supervised Instance Segmentation with Level Set Evolution 论文笔记

弱监督实例分割 Box-supervised Instance Segmentation with Level Set Evolution 论文笔记一、Abstract二、引言三、相关工作3.1 基于 Box 的实例分割3.2 基于层级的分割四、提出的方法4.1 图像分割中的层级模型4.2 基于 Box 的实例分割在 Bounding Box 内的层级进化输入的数据…...

Springboot是什么

目录 为什么会要用springboot 1、之前 2、现在 springboot优点 springboot四大核心 自动装配介绍 1、自动装配作用是什么 2、自动装配原理 springboot starter是什么 1、starter作用 2、比如:我们想搭建java web框架 3、starter原理 SpringBootApplica…...

LeetCode 134. 加油站(函数图像法 / 贪心)

题目: 链接:LeetCode 134. 加油站 难度:中等 在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中…...

王道计算机组成原理课代表 - 考研计算机 第三章 存储系统 究极精华总结笔记

本篇博客是考研期间学习王道课程 传送门 的笔记,以及一整年里对 计算机组成 知识点的理解的总结。希望对新一届的计算机考研人提供帮助!!! 关于对 存储系统 章节知识点总结的十分全面,涵括了《计算机组成原理》课程里…...

Flask-mock接口数据流程

背景:由于在开发过程中,会遇到以下的痛点 1.服务端接口提测延期,具体接口逻辑未完成实现,接口未能正常调通,导致客户端提测停滞; 2.因为前期已在技术评审上已与客户端开发定好接口字段,客户端比…...

springboot项目配置序列化,反序列化器

介绍本文介绍在项目中时间类型、枚举类型的序列化和反序列化自定义的处理类,也可以使用注解。建议枚举都实现一个统一的接口,方便处理。我这定义了一个Dict接口。枚举类型注解处理这种方式比较灵活,可以让枚举按照自己的方式序列化&#xff0…...

c++11 标准模板(STL)(std::unordered_map)(九)

定义于头文件 <unordered_map> template< class Key, class T, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator< std::pair<const Key, T> > > class unordered…...

Seay代码审计工具

一、简介Seay是基于C#语言开发的一款针对PHP代码安全性审计的系统&#xff0c;主要运行于Windows系统上。这款软件能够发现SQL注入、代码执行、命令执行、文件包含、文件上传、绕过转义防护、拒绝服务、XSS跨站、信息泄露、任意URL跳转等漏洞&#xff0c;基本上覆盖常见PHP漏洞…...

界面开发(4)--- PyQt5实现打开图像及视频播放功能

PyQt5创建打开图像及播放视频页面 上篇文章主要介绍了如何实现登录界面的账号密码注册及登录功能&#xff0c;还简单介绍了有关数据库的连接方法。这篇文章我们介绍一下如何在设计的页面中打开本地的图像&#xff0c;以及实现视频播放功能。 实现打开图像功能 为了便于记录实…...

核心系统国产平台迁移验证

核心系统国产平台迁移验证 摘要&#xff1a;信息技术应用创新&#xff0c;旨在实现信息技术领域的自主可控&#xff0c;保障国家信息安全。金融领域又是关系国家经济命脉的行业&#xff0c;而对核心交易系统的信息技术应用创新是交易所未来将要面临的重大挑战。为了推进国产化进…...

【数据结构之二叉树】——二叉树的概念及结构,特殊的二叉树和二叉树性质

文章目录一、二叉树的概念及结构1.概念2.现实中的二叉树3. 特殊的二叉树&#xff1a;3.二叉树的性质二、二叉树练习题总结一、二叉树的概念及结构 1.概念 一棵二叉树是结点的一个有限集合&#xff0c;该集合: 或者为空由一个根节点加上两棵别称为左子树和右子树的二叉树组成…...

Android学习之帧动画和视图动画

帧动画 帧动画中的每一帧其实都是一张图片&#xff0c;将许多图片连起来播放&#xff0c;就形成了帧动画。 在drawable目录下新建frmae_animation文件&#xff0c;在这个文件中定义了帧动画的每一帧要显示的图片&#xff0c;播放时&#xff0c;按从上到下显示。 <?xml v…...

vue2和vue3的区别

这周呢主要就是整理整理学的东西&#xff0c;不然看的也记不住&#xff0c;把这些学的东西做成笔记&#xff0c;感觉会清楚许多&#xff0c;这次就把vue2和vue3的区别总结一下&#xff0c;明天要考四级&#xff0c;嗐&#xff0c;本来想着复习四级&#xff0c;结果只写了一两套…...

【你不知道的事】JavaScript 中用一种更先进的方式进行深拷贝:structuredClone

你是否知道&#xff0c;JavaScript中有一种原生的方法来做对象的深拷贝? 本文我们要介绍的是 structuredClone 函数&#xff0c;它是内置在 JavaScript 运行时中的: const calendarEvent {title: "Builder.io Conf",date: new Date(123),attendees: ["Steve…...

XE开发Linux应用(二)-Webservice

新建一个工程。选择如图。继续输入服务名然后就生成对应的单元。增加linux 平台。完善对应的单元代码{ Invokable implementation File for Txaliontest which implements Ixaliontest }unit xaliontestImpl;interfaceuses Soap.InvokeRegistry, System.Types, Soap.XSBuiltIns…...

别再纠结了!KVM虚拟化实战:RAW和QCOW2磁盘格式到底怎么选?附qemu-img保姆级操作指南

KVM虚拟化存储选型实战&#xff1a;RAW与QCOW2的深度抉择与效能调优 当你的KVM虚拟机开始频繁弹出"存储空间不足"的警告&#xff0c;或是需要为关键业务系统建立可靠的快照机制时&#xff0c;面对RAW和QCOW2这两种主流磁盘格式&#xff0c;技术决策就变得尤为关键。这…...

保姆级教程:在Ubuntu 20.04上用YOLOv5 v6.2训练你自己的COCO数据集(附完整数据准备流程)

在Ubuntu 20.04上从零构建YOLOv5 v6.2自定义训练环境的完整指南 当你想在本地工作站或云服务器上训练自己的目标检测模型时&#xff0c;YOLOv5无疑是最受欢迎的选择之一。但许多教程都假设你已经熟悉了Linux环境配置、数据集处理等前置知识&#xff0c;这让不少初学者在第一步…...

Intel RealSense D435i 标定实战:从工具安装到VINS配置全流程解析

1. 准备工作&#xff1a;认识D435i与标定原理 第一次拿到Intel RealSense D435i时&#xff0c;我盯着这个火柴盒大小的设备看了半天——它凭什么能实现三维感知&#xff1f;拆开包装后发现&#xff0c;这玩意儿居然集成了双目红外相机、RGB彩色相机和IMU惯性测量单元。但问题来…...

告别虚拟机臃肿:用QEMU+OVMF在Ubuntu上快速搭建一个32MB的极简Linux内核调试环境

极简Linux内核调试环境&#xff1a;QEMUOVMF实战指南 每次打开臃肿的虚拟机都要等待漫长的启动时间&#xff0c;看着进度条缓慢爬行&#xff0c;作为开发者的你是否感到效率被无情吞噬&#xff1f;在调试内核模块或研究启动流程时&#xff0c;我们真正需要的只是一个轻量级、即…...

储能出海架构重构:摒弃传统x86工控机,基于ARM边缘节点的EMS策略下沉实战

摘要&#xff1a; 随着储能系统在全球范围的大规模部署&#xff0c;出海项目的硬件BOM成本压力与恶劣环境下的维护成本日益凸显。传统的“x86工控机下发控制 透传网关上传数据”的双体架构显得极度臃肿且易引发单点故障。本文从底层研发架构师视角出发&#xff0c;深度拆解符合…...

CherryPy与数据库集成:SQLAlchemy和ORM模式详解

CherryPy与数据库集成&#xff1a;SQLAlchemy和ORM模式详解 【免费下载链接】cherrypy CherryPy is a pythonic, object-oriented HTTP framework. https://cherrypy.dev 项目地址: https://gitcode.com/gh_mirrors/ch/cherrypy CherryPy是一个Python风格的面向对象HTTP…...

Chromatic深度解析:基于QuickJS的跨平台动态代码注入框架实现原理

Chromatic深度解析&#xff1a;基于QuickJS的跨平台动态代码注入框架实现原理 【免费下载链接】chromatic Universal modifier for Chromium/V8 | 广谱注入 Chromium/V8 的通用修改器 项目地址: https://gitcode.com/gh_mirrors/be/chromatic 你是否曾经遇到过这样的技术…...

如何轻松实现Windows风扇智能控制:5个关键技巧打造完美散热系统

如何轻松实现Windows风扇智能控制&#xff1a;5个关键技巧打造完美散热系统 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Tr…...

直面2026检测算法:英文论文降AI实战,3款工具深度避坑盘点

赶稿季来临&#xff0c;英文长稿的AI率到底该怎么降&#xff1f;不少同学愁的头都要秃了&#xff0c;不要再一个词一个词的扣了&#xff0c;这不仅慢&#xff0c;还会把好好的学术英语改得支离破碎。 坦率的讲&#xff0c;真正聪明的降ai&#xff0c;绝对不是机械替换&#xf…...

娱乐圈天降紫微星承载使命,海棠山铁哥扛起原创影视复兴大旗

一、乱世先声每一个时代的乱象&#xff0c;都需要一位天命者终结。 每一次行业的沉沦&#xff0c;都需要一束紫微星光破暗。当下影视行业&#xff0c;早已偏离创作初心&#xff0c;走入本末倒置的绝境。 翻拍泛滥成灾IP套皮横行情怀反复透支流水线作品扎堆 资本只求快速变现&am…...