观察者模式 vs 发布-订阅模式:两种设计模式的对决!

news2024/12/24 20:23:33

 

 🎬 江城开朗的豌豆:个人主页

 🔥 个人专栏 :《 VUE 》 《 javaScript 》

 📝 个人网站 :《 江城开朗的豌豆🫛 》 

⛺️ 生活的理想,就是为了理想的生活 !

在这里插入图片描述

目录

 ⭐  专栏简介

 📘  文章引言

一、观察者模式

二、发布订阅模式

三、区别

⭐  写在最后


 ⭐  专栏简介

        欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。

        同时,我们也会关注最新的前端趋势和发展动态。随着Web技术的不断演进,前端开发也在不断推陈出新。我们会及时介绍最新的前端框架、工具和技术,使你能够站在前沿,与时俱进。通过掌握最新的前端技术,你将能够在竞争激烈的Web开发领域中有更大的竞争力。

 📘  文章引言

一、观察者模式

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

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

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

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

实现代码如下:

被观察者模式

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就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)

⭐  写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设备标识牌不锈钢二维码制作

一、设备标识牌二维码好处: 1、设备信息管理:传统标识牌容纳的信息有限,将二维码用于设备标识牌,可实现设备信息丰富展示、设备文档资料可存储二维码云端、微信扫码检查查阅,无需携带纸质,同时凡尔码云端后…

JSX 动态类名控制

学习目标&#xff1a; 根据需求判断是否显示某个类名的样式 实现&#xff1a; 使用三元表达式或逻辑&&运算 import ./app.css; function App() {const color1 trueconst color2 truereturn (<div className"App">1. 三元&#xff1a;<div classN…

android项目实践说明

权限与存储 本地读取文件&#xff08;IO流&#xff09; 网络传输&#xff08;Socket通信&#xff09; 串口通信&#xff08;串行传输接口通信&#xff09; 而串口通信是应用在智能家居和单片机通信的场景&#xff0c;人脸识别门禁&#xff0c;利用串口控制门开关&#xff0…

SHELL基础编程

文章目录 SHELL基础查看有哪些解释器使用usermod修改用户解释器BASH基本特性 shell脚本的设计与运行编写问世脚本脚本格式规范执行shell脚本方法一方法二实验 变量自定义变量环境变量位置变量预定义变量 变量的扩展运用多种引号的区别双引号的应用单引号的应用反撇号或$()的应用…

leetcode 29

dividend 和 divisor都是int 类型&#xff0c;返回值也是int类型&#xff0c; 在C中&#xff0c;int类型表示整数类型&#xff0c;其范围取决于具体的实现。通常情况下&#xff0c;int类型的范围为-2147483648到2147483647&#xff0c;即-231到231-1。这是因为int类型通常为32…

Fwupd 1.9.6 Linux 固件升级工具已于近日发布

导读Fwupd 1.9.6 Linux 固件升级工具已于近日发布&#xff0c;支持更多硬件设备、新功能和十几处错误修复。 Fwupd 1.9.6 是在 fwupd 1.9.5 发布一个月后推出的&#xff0c;它引入了对更多硬件设备的支持&#xff0c;包括 AMD dGPUs Navi3x 及更高版本、Star Labs StarBook Mk …

假脸检测:Exploring Decision-based Black-box Attacks on Face Forgery Detection

论文作者&#xff1a;Zhaoyu Chen,Bo Li,Kaixun Jiang,Shuang Wu,Shouhong Ding,Wenqiang Zhang 作者单位&#xff1a;Fudan University;Yiwu Research Institute of Fudan University 论文链接&#xff1a;http://arxiv.org/abs/2310.12017v1 内容简介&#xff1a; 1&…

GeoServer改造Springboot源码二(数据源管理设计)

一、界面设计 图 1数据源管理列表 图 2选择数据源类型 1、PostGis 图 3新增PostGis数据源 2、Shapefile

Delay问题分析

【在刚刚过去的SAFe Scrum Master课程上有学员提出了Delay问题&#xff0c;进行了重点分析&#xff0c;颇有意义&#xff0c;因此整理得到本文】 大致背景情况&#xff1a;To B软件开发&#xff0c;已经启用了敏捷开发&#xff0c;迭代周期2周。 问题&#xff1a;经常出现Del…

因修改 MySQL 复制账号密码导致主从复制中断

作者 | JiekeXu 来源 |公众号 JiekeXu DBA之路&#xff08;ID: JiekeXu_IT&#xff09; 如需转载请联系授权 | (个人微信 ID&#xff1a;JiekeXu_DBA) 大家好&#xff0c;我是 JiekeXu,很高兴又和大家见面了,今天和大家一起来看看因修改 MySQL 复制账号密码导致主从复制异常&am…

Go语音中并发介绍

Go 是一种并发语言&#xff0c;而不是并行语言。在讨论 Go 中如何处理并发之前&#xff0c;我们必须首先了解什么是并发以及它与并行有何不同。 什么是并发&#xff1f; 并发性是指同时处理很多事情的能力。最好用一个例子来解释。 让我们考虑一个人慢跑。假设他早上慢跑时&…

电子画册如何制作,教你几分钟简单上手制作?

电子画册不同于纸质画册&#xff0c;它可以不受时间、空间及地域的限制&#xff0c;以更直观、新颖的形式展示在读者面前&#xff0c;还能快速传播效益。所以&#xff0c;当下&#xff0c;越来越多人想要用电子画册来传递内容信息。 如何制作电子画册&#xff1f;其实只要使用…

GoLong的学习之路(六)语法之指针

书接上回&#xff0c;上回书中写道&#xff0c;数组已经和java中数组的区别。在go中数组的是数值类型&#xff0c;故需要指针指向数组的地址&#xff0c;从而进行修改。这次诉说&#xff0c;指针 文章目录 指针指针地址new和makenewmake 指针 区别于C/C中的指针&#xff0c;G…

公立医院绩效考核系统源码,能适应医院多种绩效核算方式,技术架构:springboot、mybaits +avue +MySQL

医院绩效考核系统源码 &#xff0c;绩效核算系统全套成品源码&#xff08;有医院项目应用案例&#xff09;可适应医院多种绩效核算方式。 系统概述&#xff1a; 医院绩效考核管理系统是采用B/S架构模式设计、使用JAVA语言开发、后台使用MySql数据库进行管理的一整套计算机应用…

从零开始学习wpsjs

1.这是一个简单的wpsjs学习文档&#xff0c;我是边学习wpsjs边记录学习的&#xff0c;希望对您的学习有所帮助 开发事项&#xff1a; 全局安装wpsjs:npm install -g wpsjsWpsjs create HelloWps 安装wps npm install -g wpsjs 新建一个wps加载项 输入命令wpsjs create HelloW…

代码随想录算法训练营第三十一天丨 贪心算法part02

122.买卖股票的最佳时机 II 思路 本题首先要理清楚两点&#xff1a; 只有一只股票&#xff01;当前只有买股票或者卖股票的操作 想获得利润至少要两天为一个交易单元。 #贪心算法 这道题目可能我们只会想&#xff0c;选一个低的买入&#xff0c;再选个高的卖&#xff0c;…

LoongArch 指令集实验exp6

在借鉴了友佬的代码后&#xff0c;终于是跑通了测试。 1. 2. 4. 5. 6. 还需要改一个&#xff08;&#xff09; assign sr64_result {{32{op_sra & alu_src1[31]}}, alu_src1[31:0]} >> alu_src2[4:0]; //rj >> i5

Panoply启动报错A Java Exception has occurred

Panoply启动报错A Java Exception has occurred 问题描述 原因 可能是版本不对&#xff0c;目前panoly只支持java11以后的了&#xff0c;我的java是8的&#xff0c;需要升级。 解决方案 删除原有的Java8重新安装Java11之后&#xff0c;即打开成功 安装Java11步骤

抓取网页的含义和URL基本构成

抓取网页是指通过爬虫程序从互联网上获取网页的内容和数据。抓取网页是爬虫的核心功能之一&#xff0c;通过抓取网页&#xff0c;可以获取到网页中的文本、图片、链接等信息&#xff0c;用于后续的数据分析、挖掘和应用。 URL&#xff08;Uniform Resource Locator&#xff09…

了解并使用 jetty

前言 Jetty 是 Eclipse 基金会下的一个开源项目&#xff0c;它是一款用Java实现的、基于标准的HTTP服务器和JAVA Servlet容器。其优秀的性能和强大的可配置性使其在构建复杂和大规模的应用程序中非常受欢迎。在此篇文章中&#xff0c;我们将深入了解 Jetty&#xff0c;以及它如…