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

JavaScript 简单实现观察者模式和发布订阅模式

JavaScript 简单实现观察者模式和发布订阅模式

  • 1. 观察者模式
    • 1.1 如何理解
    • 1.2 代码实现
  • 2. 发布订阅模式
    • 2.1 如何理解
    • 2.2 代码实现

1. 观察者模式

1.1 如何理解

概念:观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

如何理解这句话呢?来举个生活中的例子

学生小明情绪比较容易波动,所以当小明的情绪发生变化时,父母和老师希望及时获得通知,以便可以采取适当的措施来帮助他。

  • 首先家长和老师(观察者)都会告诉小明他们对他的情绪状态很关注。(订阅事件)
  • 当小明(被观察者)的情绪发生变化时,他会通知所有注册过的观察者。例如,如果小明感到很开心,他会告诉父母和老师:“我今天心情很好!”;如果他感到沮丧,他也会告诉父母和老师:“我今天感觉不太好。”(通知变化)

这样父母和老师就能及时了解小明的情绪状态,当小明情绪低落时,他们可以给予他关心、安慰和支持。
在这个例子中,小明就是被观察者,而父母和老师都是观察者。

1.2 代码实现

下面就来简单实现一下它的代码。

class Subject {// 被观察者 学生constructor() {this.state = "happy";this.observers = []; // 存储所有的观察者}//新增观察者add(o) {this.observers.push(o);}// 更新状态setState(newState) {// 更新状态后通知this.state = newState;this.notify();}//通知所有的观察者notify() {this.observers.forEach((o) => o.update(this));}
}class Observer {// 观察者 父母和老师constructor(name) {this.name = name;}//通知更新update(student) {console.log(`亲爱的${this.name} 通知您当前学生的状态是${student.state}`);}
}//创建被观察者学生
let student = new Subject("学生");
//创建观察者父母和老师
let parent = new Observer("父母");
let teacher = new Observer("老师");
//给被观察者学生增加观察者
student.add(parent);
student.add(teacher);student.setState("sad");
//亲爱的父母 通知您当前学生的状态是sad
//亲爱的老师 通知您当前学生的状态是sad

2. 发布订阅模式

2.1 如何理解

发布订阅模式跟观察者模式很像,它们其实都有发布者订阅者,但是他们是有区别的:

  • 观察者模式的发布和订阅是互相依赖的
  • 发布订阅模式的发布和订阅是不互相依赖的,因为有一个统一调度中心

为了更好区分这两种设计模式,接着上述例子。

  • 所有老师都希望订阅小明的情绪状态,他们向情绪监测系统注册自己,来时刻关注小明的情绪。(向调度中心订阅事件)
  • 当小明的情绪发生变化时,情绪监测系统会将消息发布给所有订阅了小明情绪状态的老师。例如,如果小明在上课时感到烦躁,情绪监测系统会发布消息给老师:“小明情绪不稳定,请关注他的情绪变化。”(调度中心通知变化)

通过发布订阅模式,小明不需要直接告诉每位老师他的情绪状态,而是通过情绪监测系统自动发布消息给所有订阅了他情绪状态的老师。这种发布者不直接接触到订阅者的模式,就是发布订阅模式。
在这里插入图片描述
那么发布订阅模式有何应用呢?
Vue的EventBus全局事件总线其实就是用了发布订阅模式。用法如下:
1.安装全局事件总线

new Vue({el:"#root",render: h => h(App),beforeCreate() {Vue.prototype.$bus = this //安装全局事件总线}
}) 

2.订阅事件

this.bus.$on('someEvent', func)

3.发布事件

this.bus.$emit('someEvent', params)

那么接下来就来手动实现一个EventBus。

2.2 代码实现

主要思路:

  • 创建一个缓存列表对象,存放订阅的事件名和回调
  • on 方法用来把回调函数都加到缓存列表中(订阅者注册事件到调度中心)
  • emit方法根据事件名去逐个执行对应缓存列表中的函数(发布者发布事件到调度中心)
  • off 方法取消相应事件订阅(取消订阅)
  • once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)
class EventEmitter {constructor() {// 缓存列表,用来存放注册的事件与回调this.cache = {};}// 订阅事件on(name, cb) {// 如果当前事件没有订阅过,就给事件创建一个队列if (!this.cache[name]) {this.cache[name] = []; //由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列}this.cache[name].push(cb); }// 触发事件emit(name, ...args) {// 检查目标事件是否有监听函数队列if (this.cache[name]) {// 如果有,则逐个调用队列里的回调函数this.cache[name].forEach((callback) => {callback(...args);});}}// 取消订阅off(name, cb) {const callbacks = this.cache[name]; const index = callbacks.indexOf(cb); if (index !== -1) {callbacks.splice(index, 1); }}// 只订阅一次once(name, cb) {// 回调函数执行后,取消订阅当前事件const wrapper = (...args) => {cb(args); this.off(name, wrapper); };this.on(name, wrapper);}
}//测试
let eventBus = new EventEmitter();
//1.测试订阅,触发以及取消订阅
let test1 = function (...args) {console.log("test1", args);
};
eventBus.on("test", test1); //订阅事件
eventBus.emit("test", 1, 2, 3, 4, 5); //触发事件 test1 [ 1, 2, 3, 4, 5 ]
eventBus.emit("test", 6, 7, 8, 9); //触发事件 test1 [ 6, 7, 8, 9 ]
eventBus.off("test", test1); // 取消订阅
eventBus.emit("test", 10, 11, 12);
//2.测试只订阅一次
let test2 = function (...args) {console.log("test2", args);
};
eventBus.once("test", test2); //只订阅一次
eventBus.emit("test", 1, 2, 3, 4, 5); //test2 [ 1, 2, 3, 4, 5 ]
eventBus.emit("test", 6, 7, 8, 9);

相关文章:

JavaScript 简单实现观察者模式和发布订阅模式

JavaScript 简单实现观察者模式和发布订阅模式 1. 观察者模式1.1 如何理解1.2 代码实现 2. 发布订阅模式2.1 如何理解2.2 代码实现 1. 观察者模式 1.1 如何理解 概念:观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时&#xff…...

高通WLAN框架学习(37)-- TDLS(Tunneled Direct Link Setup)通道直接链路建立

一 TDLS概述 隧道直连设置(TDLS)基于IEEE 802.11z-2010IEEE标准802.11z标准(无线局域网介质访问控制(MAC)和物理层(PHY)规范。 TDLS允许与同一AP关联的设备之间建立直接链路。Wi-Fi Direct允许设备之间直接连接,而不需要AP。Wi-Fi联盟认证可用于IEEE 802.11a和802.11g设备的T…...

高算力AI模组前沿应用:基于ARM架构的SoC阵列式服务器

本期我们带来高算力AI模组前沿应用,基于ARM架构的SoC阵列式服务器相关内容。澎湃算力、创新架构、异构计算,有望成为未来信息化社会的智能算力底座。 ▌性能优势AI驱动,ARM架构服务器加速渗透 一直以来,基于ARM架构的各类处理器…...

老年公寓人员定位管理系统:提升安全与关怀的智能解决方案

老年公寓作为提供安全居住环境和关怀服务的重要场所,面临着人员管理和安全控制的挑战。为了解决这些问题,老年公寓人员定位管理系统应运而生。基于为提供全面的安全管理和个性化关怀服务,华安联大便通过老年公寓人员定位管理系统的技术原理、…...

每日一题之两个字符串的删除操作

题目链接 给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 **相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 示例 1: 输入: word1 "sea", word2 "eat" 输出: 2 解释: 第一步将 "sea" 变…...

nacos安装与基础配置

源码 https://github.com/alibaba/nacos https://gitee.com/mirrors/Nacos 编译 git clone https://github.com/alibaba/nacos.git cd nacos/ mvn -Prelease-nacos -Dmaven.test.skiptrue clean install -U ls -al distribution/target/// change the $version to your ac…...

GitHub Copilot:让开发编程变得像说话一样简单

引用: 人类天生就梦想、创造、创新。但今天,我们花太多时间被繁重的工作所消耗,花在消耗我们时间、创造力和精力的任务上。为了重新连接我们工作的灵魂,我们不仅需要一种更好的方式来做同样的事情,更需要一种全新的工…...

并发编程中锁的优化

在 Java 并发编程中,锁是一种常用的同步机制,用于控制对共享资源的访问。使用锁可以确保多个线程之间的互斥访问,避免数据竞争和并发问题。 然而,锁的使用可能会带来一定的性能开销,特别是在高并发场景下。 为了优化…...

笔试题:统计字符串中某字符串在其出现的字符个数

笔试题:统计字符串中某一子串的字符个数:例如字符串aabbcd,有aabb:4,ab:2 哈哈,这道题是小编面试音视频龙头企业的笔试题,以下是我写的代码:如果有错误,希望可以指正!!! 解题思路:利用双指针i和…...

Java NIO Files类读取文件流方式详解

Java NIO Files类读取文件流方式详解 Files类原理概述 java.nio.file.Files是Java标准库提供的一个工具类,用于操作文件和目录。它提供了一系列静态方法,可以用于创建、复制、删除、移动、重命名、读取、写入文件和目录等常见的文件系统操作。同时&…...

Mybatis快速入门,Mybatis的核心配置文件

Mybatis快速入门 一、Mybatis简介1.1Mybatis简化JDBC 二、Mybatis快速入门2.1创建user表,添加数据2.2创建模块,导入坐标2.3编写Mybatis核心配置文件 --> 替换连接信息,解决硬编码问题2.4编写SQL映射文件 --> 统一管理sql语句&#xff0…...

go语言中defer执行顺序

defer 执行顺序和调用顺序相反,类似于栈后进先出。 defer在 return 之后执行,但在函数推出之前,defer可以修改返回值。 func test() int {i : 0defer func() {fmt.Println("defer1")}()defer func() {i 1fmt.Println("defe…...

webpack xxx is not a constructor

环境 webpack5.88.2 vue-router 按需引入 原因 模块循环引用导致 有A B C三个模块 A B模块import C 中导出的class c又依赖B 中Class 的方法 B 又依赖C中的class 此时会导致import 的 C 为undefined...

安装支持vs2019的MFC(解决MSBuild 错误 MSB8041、MSB8042)

安装支持MFC的vs2019(解决MSBuild 错误 MSB8041、MSB8042) 常用安装选项解决MSBuild 错误 常用安装选项 解决MSBuild 错误 安装上述勾选内容后,即可解决MSBuild 错误 MSB8041 MSB8041:此项目需要 MFC/ATL 库。 https://learn.mic…...

校园电气安全风险分析及预防措施 安科瑞 许敏

摘要:校园属于人员密集场所,若安全风险排查、管控不到位,可能导致安全事故发生,造成严重事故后果。校园电气设备设施引起的电气火灾和触电等事故,是构成校园安全威胁之一,笔者通过对校园发生的电气安全事故案例原因分析…...

机器学习之十大经典算法

机器学习算法是计算机科学和人工智能领域的关键组成部分,它们用于从数据中学习模式并作出预测或做出决策。本文将为大家介绍十大经典机器学习算法,其中包括了线性回归、逻辑回归、支持向量机、朴素贝叶斯、决策树等算法,每种算法都在特定的领…...

系统架构设计师 11:未来信息综合技术

本章花了很多笔墨来写各项技术的发展历程,可以了解一下。 一、信息物理系统 信息物理系统(Cyber-Physical Systems,CPS)是控制系统、嵌入式系统的扩展与延伸。 CPS典型的应用场景有:健康管理、智能维护、远程征兆性…...

Docker 数据管理[文件互访] 端口映射[暴露端口提供服务] 容器互联[指定容器名防止IP变动]

Docker 的数据管理 管理 Docker 容器中数据主要有两种方式:数据卷(Data Volumes)和数据卷容器(DataVolumes Containers)。 1.数据卷(宿主机与容器间传输 防止删除容器后数据丢失) 数…...

【stable diffusion】保姆级入门课程04-Stable diffusion(SD)图生图-局部重绘的用法

目录 0.本章素材 1.什么是局部重绘 2.局部重绘和涂鸦有什么不同 3.操作界面讲解 3.1.蒙版模糊 3.2.蒙版模式 3.3.蒙版蒙住的内容 3.4.重绘区域 4.局部重绘的应用(面部修复) 5.课后训练 0.本章素材 chilloutmix模型(真人模型)百度地址&#xf…...

制作Java8环境Docker镜像

制作Java8环境Docker镜像 这里介绍如何制作一个java8环境的镜像,用于运行java应用程序。 1.安装包 这里采用OpenJDK,不会涉及版本问题。 同样思源中文字体也是开源的,没有版权问题。 OpenJDK8:OpenJDK8U-jdk_x64_linux_hotsp…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

零基础设计模式——行为型模式 - 责任链模式

第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用

中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...