设计模式之发布订阅、观察者模式

一、观察者模式

观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新

观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯

例如生活中,我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸

报社和订报纸的客户就形成了一对多的依赖关系

实现代码如下:

被观察者模式

class Subject {constructor() {this.observerList = [];}addObserver(observer) {this.observerList.push(observer);}removeObserver(observer) {const index = this.observerList.findIndex(o => o.name === observer.name);this.observerList.splice(index, 1);}notifyObservers(message) {const observers = this.observeList;observers.forEach(observer => observer.notified(message));}}

观察者:

class Observer {constructor(name, subject) {this.name = name;if (subject) {subject.addObserver(this);}}notified(message) {console.log(this.name, 'got message', message);}
}

使用代码如下:

const subject = new Subject();
const observerA = new Observer('observerA', subject);
const observerB = new Observer('observerB');
subject.addObserver(observerB);
subject.notifyObservers('Hello from subject');
subject.removeObserver(observerA);
subject.notifyObservers('Hello again');

上述代码中,观察者主动申请加入被观察者的列表,被观察者主动将观察者加入列表

二、发布订阅模式

发布-订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在

同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者存在

实现代码如下:

class PubSub {constructor() {this.messages = {};this.listeners = {};}// 添加发布者publish(type, content) {const existContent = this.messages[type];if (!existContent) {this.messages[type] = [];}this.messages[type].push(content);}// 添加订阅者subscribe(type, cb) {const existListener = this.listeners[type];if (!existListener) {this.listeners[type] = [];}this.listeners[type].push(cb);}// 通知notify(type) {const messages = this.messages[type];const subscribers = this.listeners[type] || [];subscribers.forEach((cb, index) => cb(messages[index]));}
}

发布者代码如下:

class Publisher {constructor(name, context) {this.name = name;this.context = context;}publish(type, content) {this.context.publish(type, content);}
}

订阅者代码如下:

class Subscriber {constructor(name, context) {this.name = name;this.context = context;}subscribe(type, cb) {this.context.subscribe(type, cb);}
}

使用代码如下:

const TYPE_A = 'music';
const TYPE_B = 'movie';
const TYPE_C = 'novel';const pubsub = new PubSub();const publisherA = new Publisher('publisherA', pubsub);
publisherA.publish(TYPE_A, 'we are young');
publisherA.publish(TYPE_B, 'the silicon valley');
const publisherB = new Publisher('publisherB', pubsub);
publisherB.publish(TYPE_A, 'stronger');
const publisherC = new Publisher('publisherC', pubsub);
publisherC.publish(TYPE_C, 'a brief history of time');const subscriberA = new Subscriber('subscriberA', pubsub);
subscriberA.subscribe(TYPE_A, res => {console.log('subscriberA received', res)
});
const subscriberB = new Subscriber('subscriberB', pubsub);
subscriberB.subscribe(TYPE_C, res => {console.log('subscriberB received', res)
});
const subscriberC = new Subscriber('subscriberC', pubsub);
subscriberC.subscribe(TYPE_B, res => {console.log('subscriberC received', res)
});pubsub.notify(TYPE_A);
pubsub.notify(TYPE_B);
pubsub.notify(TYPE_C);

上述代码,发布者和订阅者需要通过发布订阅中心进行关联,发布者的发布动作和订阅者的订阅动作相互独立,无需关注对方,消息派发由发布订阅中心负责

三、区别

两种设计模式思路是一样的,举个生活例子:

  • 观察者模式:某公司给自己员工发月饼发粽子,是由公司的行政部门发送的,这件事不适合交给第三方,原因是“公司”和“员工”是一个整体
  • 发布-订阅模式:某公司要给其他人发各种快递,因为“公司”和“其他人”是独立的,其唯一的桥梁是“快递”,所以这件事适合交给第三方快递公司解决

上述过程中,如果公司自己去管理快递的配送,那公司就会变成一个快递公司,业务繁杂难以管理,影响公司自身的主营业务,因此使用何种模式需要考虑什么情况两者是需要耦合的

两者区别如下图:

  • 在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。

  • 在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。

  • 观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/190565.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023.11-9 hive数据仓库,概念,架构,元数据管理模式

目录 0.数据仓库和数据库 数据仓库和数据库的区别 数据仓库基础三层架构 一.HDFS、HBase、Hive的区别 二.大数据相关软件 三. Hive 的优缺点 1)优点 2)缺点 四. Hive 和数据库比较 1)查询语言 2)数据更新 3)…

csharp写一个招聘信息采集的程序

csharp爬虫是一种用于自动化抓取网页内容的程序。它可以通过模拟人类浏览器的行为,自动访问网站并抓取所需的数据。csharp爬虫可以用于各种场景,例如数据挖掘、搜索引擎优化、竞争情报等。但是,使用csharp爬虫需要注意一些问题,例…

Python语言的十大特性。

文章目录 前言一、Python二、Python 编程语言的特性三、开源四、Python 中的 GUI 编程支持五、Python 支持高级语言六、可扩展性七、可移植性八、大型标准库九、解释性语言十、面向对象程序设计语言十一、表达力十二、常见问题总结Python技术资源分享1、Python所有方向的学习路…

Flink在汽车行业的应用【面试加分系列】

很多同学问我为什么要发这些大数据前沿汇报? 一方面是自己学习完后觉得非常好,然后总结发出来方便大家阅读;另外一方面,看这些汇报对你的面试帮助会很大,特别是面试前可以看看即将面试公司在大数据前沿的发展动向&…

【C++入门篇】保姆级教程篇【下】

目录 一、运算符重载 1)比较、赋值运算符重载 2) 流插入留提取运算符重载 二、剩下的默认成员函数 1)赋值运算符重载 2)const成员函数 3)取地址及const取地址操作符重载 三、再谈构造函数 1)初始化列表 …

【OpenCV实现图像:用OpenCV图像处理技巧之白平衡算法】

文章目录 概要加载样例图像统计数据分析White Patch Algorithm小结 概要 白平衡技术在摄影和图像处理中扮演着至关重要的角色。在不同的光照条件下,相机可能无法准确地捕捉到物体的真实颜色,导致图像呈现出暗淡、色调不自然或者褪色的效果。为了解决这个…

Ubuntu取消sudo的输入密码

Ubuntu最近要安装软件,每次sudo都要输入一次密码,感觉很麻烦,于是想能不能设置为不输入密码,在网上找了一下解决办法。 主要参考这篇文章: Ubuntu取消sudo时输入密码 上面这篇文章使用的是vim,但是按照博…

【MySQL日志与备份篇】数据库备份与恢复

数据库备份与恢复 文章目录 数据库备份与恢复1. 物理备份与逻辑备份2. mysqldump实现逻辑备份2.1 备份一个数据库2.2 备份全部数据库2.3 备份部分数据库2.4 备份部分表2.5 备份单表的部分数据2.6 排除某些表的备份2.7 只备份结构或只备份数据2.8 备份中包含存储过程、函数、事件…

合成数据如何改变制造业

人工智能正在工厂车间使用,以识别生产线中的低效率。它可以有效地预测设备何时需要维护,以避免停机。人工智能被用于发现产品中的缺陷。 为了完成所有这些工作,使用从人工智能应该学习的过程中收集的数据来创建或训练模型。对于缺陷识别&…

Android Glide transform圆形图CircleCrop动态代码描边绘制外框线并rotateImage旋转,Kotlin

Android Glide transform圆形图CircleCrop动态代码描边绘制外框线并rotateImage旋转&#xff0c;Kotlin <?xml version"1.0" encoding"utf-8"?> <FrameLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app&q…

java网络编程之UDP协议

文章目录 UDP简介一发一收客户端&#xff1a;服务端&#xff1a; 多发多收实现多开客户端&#xff1a;服务端 UDP简介 UDP&#xff08;User Datagram Protocol&#xff09; DatagramSocket 用于创建客户端、服务端DatagramSocket() :创建客户端的Socket对象&#xff0c;系统随…

Adobe premiere裁剪视频尺寸并转为GIF格式

第 1 步&#xff1a;裁剪视频 修改序列设置以适应裁剪之后的图像区域&#xff1b;序列中的编辑模式不能使用默认的&#xff0c;这里使用的是“ProRes RAW” 第 2 步&#xff1a;设置背景色 需要设置“颜色遮罩”的大小和颜色&#xff0c;颜色遮罩放在下面。 第 3 步&#xff1…

【Git】第四篇:基本操作(理解工作区、暂存区、版本库)

Git 工作区、暂存区和版本库 工作区&#xff1a;就是我们创建的本地仓库所在的目录暂存区&#xff1a; stage或index&#xff0c;一般放在.git(可隐藏文件)目录下的index文件&#xff08;.git/index&#xff09;中&#xff0c;所以我们把暂存区有时候也叫做索引&#xff08;in…

Html 引入element UI + vue3 报错Failed to resolve component: el-button

问题&#xff1a;Html 引入element UI vue3 &#xff0c;el-button效果不出来 <!DOCTYPE html> <html> <head><meta charset"UTF-8"><!-- import Vue before Element --> <!-- <script src"https://unpkg.com/vue2/dist…

CCLink转Modbus TCP网关_CCLINK参数配置

CCLink转Modbus TCP网关&#xff08;XD-ETHCL20&#xff09;&#xff0c;具有CCLINK主从站功能。主要用途是将各种MODBUS-TCP设备接入到CCLINK总线中。它可以作为从站连接到CCLINK总线上&#xff0c;也可以作为主站或从站连接到MODBUS-MTP总线上。 1、 配置网关的CCLINK参数&am…

岗前酒精检测仪

岗前酒精检测仪&#xff1a;集“酒精检测智能测温人脸考勤”三合一智能检测仪。 酒精检测功能&#xff1a;采用电化学传感器检测检测酒精浓度&#xff0c;具有吹气中断及吹气流量侦测&#xff0c;吹气防欺骗设计&#xff0c;吹气温度及吸气侦测&#xff1b;响应时间≤20毫秒&am…

Unity中Shader雾效的实现方法一

文章目录 前言一、在片元着色器中使用如下公式计算最终的颜色 lerp(雾效颜色&#xff0c;物体颜色&#xff0c;雾效混合因子)1、获取雾效颜色2、物体的颜色一般通过纹理采样得到&#xff0c;此处用 1 代替测试3、获取 雾效混合因子&#xff08;由 雾的距离 和 雾的浓度决定&am…

代码随想录算法训练营第18天|513. 找树左下角的值 112. 路径总和 113.路径总和ii 106.从中序与后序遍历序列构造二叉树

JAVA代码编写 513. 找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7提示: 二叉树的节点个…

安全框架SpringSecurity-2(集成thymeleaf集成验证码JWT)

一、SpringSecurity 集成thymeleaf ①&#xff1a;复制并修改工程 复制04_spring_security并重命名为05_spring_security_thymeleaf ②&#xff1a;添加配置和依赖 添加thymeleaf依赖 <dependency><groupId>org.springframework.boot</groupId><artif…

Scala中编写多线程爬虫程序并做可视化处理

目录 一、引言 二、Scala爬虫程序的实现 1、引入必要的库 2、定义爬虫类 3、可视化处理 三、案例分析&#xff1a;使用Scala爬取并可视化处理电影数据 1、定义爬虫类 2、实现爬虫程序的控制逻辑 3、可视化处理电影数据 四、总结 一、引言 随着互联网的快速发展&#…