我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

1. 观察者模式

1.1 什么是观察者模式

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

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

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

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

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

1.2 代码实现

观察者模式有何应用呢?

Vue的响应式就是基于观察者模式的,下面就来简单实现一下它的代码。

// 被观察者 学生class Subject {  constructor() {    this.state = "happy";    this.observers = []; // 存储所有的观察者  }  //新增观察者  add(o) {    this.observers.push(o);  }  //获取状态  getState() {    return this.state;  }  // 更新状态并通知  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.getState()}`);  }}let student = new Subject();let parent = new Observer("父母");let teacher = new Observer("老师");//添加观察者student.add(parent);student.add(teacher);//设置被观察者的状态student.setState("sad");

在这里插入图片描述

2. 发布-订阅模式

2.1 什么是发布-订阅模式

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

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

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

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

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

// main.jsimport Vue from "vue"Vue.prototype.$bus = new Vue()

通过on订阅事件

//组件Aexport default{    mounted(){        // 监听事件的触发        this.$bus.$on("sendMsg", data => {            console.log(data)//身体健康        })    },    beforeDestroy(){        // 取消监听        this.$bus.$off("sendMsg")    }}

通过emit发布事件

//组件B<template>    <button @click="handlerClick">点击发送数据</button></template>export default{    methods:{        handlerClick(){            this.$bus.$emit("sendMsg", "身体健康")        }    }}

了解了EventBus的使用后,那么接下来就来手动实现一个EventBus。

2.2 代码实现

2.2.1 基础版

实现目标:使用 $on 订阅事件,使用 $emit 发布事件。
主要思路:

  • 创建一个缓存列表对象,存放订阅的事件名和回调
  • on 方法用来把回调函数都加到缓存列表中(订阅者注册事件到调度中心)
  • emit方法根据事件名去逐个执行对应缓存列表中的函数(发布者发布事件到调度中心)
class EventBus {  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);      });    }  }}// 测试let eventBus = new EventBus();// 订阅事件eventBus.on("teacherName1", (pos, state) => {  console.log(`订阅者小陈老师,小明同学当前在${pos},心情状态是${state}`);});eventBus.on("teacherName1", (pos, state) => {  console.log(`订阅者小陈老师,小明同学当前在${pos},心情状态是${state}`);});eventBus.on("teacherName2", (pos, state) => {  console.log(`订阅者小李老师,小明同学当前在${pos},心情状态是${state}`);});// 发布事件eventBus.emit("teacherName1", "教室", "伤心");eventBus.emit("teacherName2", "操场", "开心");

输出结果:

在这里插入图片描述

2.2.2 取消订阅

实现目标:增加 off 方法取消订阅。

  • off 方法:找到当前取消事件名对应的函数队列中相应回调,进行删除
class EventBus {  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);     }  }}// 测试let eventBus = new EventBus();let event1 = function (...args) {  console.log(`通知1-订阅者小陈老师,小明同学当前心情状态:${args}`)};let event2 = function (...args) {  console.log(`通知2-订阅者小陈老师,小明同学当前心情状态:${args}`)};// 订阅事件eventBus.on("teacherName1", event1);eventBus.on("teacherName1", event2);// 取消订阅事件1eventBus.off('teacherName1', event1);// 发布事件eventBus.emit("teacherName1", "教室", "上课", "打架", "愤怒");eventBus.emit("teacherName2", "教室", "上课", "打架", "愤怒");

输出结果:

在这里插入图片描述

2.2.3 订阅一次

实现目标:增加 once 方法只订阅一次。

  • once 方法只监听一次,执行完第一次回调函数后,自动删除当前订阅事件
class EventBus {  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 fn = (...args) => {      cb(...args);       this.off(name, fn);     };    this.on(name, fn);  }}// 测试let eventBus = new EventBus();let event1 = function (...args) {  console.log(`通知1-订阅者小陈老师,小明同学当前心情状态:${args}`)};// 订阅事件,只订阅一次eventBus.once("teacherName1", event1);// 发布事件eventBus.emit("teacherName1", "教室", "上课", "打架", "愤怒");eventBus.emit("teacherName1", "教室", "上课", "打架", "愤怒");eventBus.emit("teacherName1", "教室", "上课", "打架", "愤怒");

输出结果:

在这里插入图片描述

写作不易,你的一赞一评,就是我前行的最大动力。如有问题,欢迎指出!

来源地址:https://blog.csdn.net/weixin_43288600/article/details/131968091

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

JavaScript 简单实现观察者模式和发布-订阅模式 1. 观察者模式1.1 什么是观察者模式1.2 代码实现 2. 发布-订阅模式2.1 什么是发布-订阅模式2.2 代码实现2.2.1 基础版2.2.2 取消订阅2.2.3
2023-08-21

JavaScript观察者模式:巧用发布-订阅机制,实现松耦合设计

观察者模式是一种设计模式,它允许对象订阅其他对象的事件,以便在事件发生时收到通知。这种模式可以帮助您创建松散耦合的应用程序,因为观察者和被观察者之间没有直接的依赖关系。
JavaScript观察者模式:巧用发布-订阅机制,实现松耦合设计
2024-02-03

怎么用Javascript实现观察者模式

本篇内容主要讲解“怎么用Javascript实现观察者模式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么用Javascript实现观察者模式”吧!什么是观察者模式?观察者模式一种设计模式。观
2023-06-21

JavaScript设计模式中的观察者模式怎么实现

本文小编为大家详细介绍“JavaScript设计模式中的观察者模式怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“JavaScript设计模式中的观察者模式怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知
2023-07-02

javascript设计模式中的订阅者模式怎么实现

本篇内容介绍了“javascript设计模式中的订阅者模式怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一. 初识代理模式代理模式是
2023-06-26

spring发布订阅模式怎么实现

在Spring中,可以使用Spring的事件机制来实现发布订阅模式。创建事件对象:首先,需要创建一个事件对象,该对象包含了需要发布的数据。public class CustomEvent extends ApplicationEvent {
spring发布订阅模式怎么实现
2024-02-29

JavaScript观察者模式:掌控事件流,实现数据同步

JavaScript观察者模式是一种设计模式,允许对象订阅并响应其他对象的事件。它是一种有效且灵活的方式来管理事件流,实现数据同步。本文将介绍JavaScript观察者模式的原理、实现方法和应用场景。
JavaScript观察者模式:掌控事件流,实现数据同步
2024-02-03

揭秘JavaScript观察者模式:轻松实现跨组件通信

JavaScript观察者模式是一种设计模式,它允许对象之间进行通信,而不必知道彼此的存在。这种模式非常适合用于构建松散耦合的应用程序。
揭秘JavaScript观察者模式:轻松实现跨组件通信
2024-02-03

Java实现数据更新和事件通知的观察者模式

Java观察者模式是一种行为型设计模式,用于实现对象间的一对多依赖关系。当一个对象的状态发生改变时,它的所有依赖对象都会收到通知并自动更新。观察者模式可以实现松耦合,增强了系统的可维护性和可拓展性
2023-05-17

C#基于自定义事件EventArgs怎么实现发布订阅模式

这篇文章主要介绍“C#基于自定义事件EventArgs怎么实现发布订阅模式”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C#基于自定义事件EventArgs怎么实现发布订阅模式”文章能帮助大家解决问
2023-06-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录