JavaScript观察者模式(publish/subscribe)原理与实现方法

yizhihongxing

JavaScript观察者模式(publish/subscribe)原理与实现方法

观察者模式,也叫发布订阅模式,是一种对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。这种设计模式在前端开发中应用广泛,比如实现事件监听、多模块协同、组件间通信等。

原理

观察者模式包含如下角色:

  • 主题(Subject):在其中定义一个添加、删除和通知观察者对象的接口。
  • 观察者(Observer):定义一个叫做update()的接口,当接收到主题发来的通知时被调用。
  • 具体主题(ConcreteSubject):将有关状态存到具体观察者对象;在有状态变化时,给每个观察者发出通知。
  • 具体观察者(ConcreteObserver):实现观察者接口,保存有关主题的状态,具体主题对象发生变化时更新自己的状态。

具体实现过程:

  1. 创建主题类,包含添加、删除观察者、通知观察者的方法。
class Subject {
  constructor() {
    this.observers = new Set() // Set保证不重复
  }

  // 添加观察者
  addObserver(observer) {
    this.observers.add(observer)
  }

  // 删除观察者
  removeObserver(observer) {
    this.observers.delete(observer)
  }

  // 通知观察者
  notify(data) {
    for (const observer of this.observers) {
      observer.update(data)
    }
  }
}
  1. 创建观察者类,包含update()方法。
class Observer {
  update(data) {
    // 处理业务逻辑
  }
}
  1. 创建具体主题类,继承自主题类,实现具体状态变化时通知观察者的方法。
class ConcreteSubject extends Subject {
  constructor() {
    super()
    this.state = '' // 保存状态
  }

  // 具体状态变化时通知观察者
  setState(state) {
    if (this.state !== state) {
      this.state = state
      this.notify(state)
    }
  }
}
  1. 创建具体观察者类,继承自观察者类,实现update()方法。
class ConcreteObserver extends Observer {
  constructor() {
    super()
    this.state = ''
  }

  update(data) {
    this.state = data
    // 处理业务逻辑
  }
}
  1. 使用时,先创建具体主题对象,再创建具体观察者对象并添加到主题的观察者列表,通过调用具体主题对象的setState()方法来触发通知。
const subject = new ConcreteSubject()

const observer1 = new ConcreteObserver()
subject.addObserver(observer1)

const observer2 = new ConcreteObserver()
subject.addObserver(observer2)

subject.setState('state1') // 通知所有观察者更新状态

实现方法

除了上述的基本实现外,观察者模式还有一些常见的变种实现方法,如:使用事件监听机制实现、使用回调函数实现等。

使用事件监听机制实现

使用DOM事件监听机制实现观察者模式,代码如下:

class Subject {
  constructor() {
    this.handlers = {}
    this.id = 0
  }

  // 添加订阅者
  addEventListener(type, handler) {
    if (!this.handlers[type]) {
      this.handlers[type] = []
    }
    this.handlers[type].push({ id: ++this.id, handler })
  }

  // 移除订阅者
  removeEventListener(type, id) {
    if (this.handlers[type]) {
      this.handlers[type] = this.handlers[type].filter(
        item => item.id !== id
      )
    }
  }

  // 发布消息
  dispatchEvent(type, data) {
    if (this.handlers[type]) {
      this.handlers[type].forEach(item => {
        item.handler(data)
      })
    }
  }
}

使用时,将具体观察者对象的业务逻辑封装成回调函数,然后作为订阅者加入到主题对象的事件监听列表中。

const subject = new Subject()

function callback1(data) {
  // 处理业务逻辑
}

function callback2(data) {
  // 处理业务逻辑
}

subject.addEventListener('change', callback1)
const id = subject.id // 记录订阅者ID
subject.addEventListener('change', callback2)

subject.dispatchEvent('change', 'data') // 发布消息

subject.removeEventListener('change', id) // 移除订阅者

使用回调函数实现

使用回调函数实现观察者模式,代码如下:

class Subject {
  constructor() {
    this.callbacks = []
  }

  // 添加订阅者
  subscribe(callback) {
    this.callbacks.push(callback)
  }

  // 移除订阅者
  unsubscribe(callback) {
    this.callbacks.splice(this.callbacks.indexOf(callback), 1)
  }

  // 发布消息
  notify(data) {
    this.callbacks.forEach(callback => {
      callback(data)
    })
  }
}

与上一种实现方式不同的是,具体观察者对象的业务逻辑直接封装在回调函数中,然后作为订阅者加入到主题对象的回调函数列表中。

const subject = new Subject()

function callback1(data) {
  // 处理业务逻辑
}

function callback2(data) {
  // 处理业务逻辑
}

subject.subscribe(callback1)
subject.subscribe(callback2)

subject.notify('data') // 发布消息

subject.unsubscribe(callback2) // 移除订阅者

以上就是JavaScript观察者模式(publish/subscribe)的原理与实现方法的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript观察者模式(publish/subscribe)原理与实现方法 - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • vue 实现可拖曳的树状结构图

    初步了解: Vue.js 是一个用来构建用户界面的渐进式框架,Vue.js 的核心是 MVVM 模式,数据更新驱动着视图渲染,可以非常方便地处理数据和 DOM 元素的交互。 在本次实现中,我们需要用到 Vue.js 的指令、组件、事件机制等功能进行开发。 第一步:确定开发思路 在 Vue.js 中实现可拖曳的树状结构图,可以将其分为三个部分: 树形结构的展示…

    Vue 2023年5月29日
    00
  • 详解Nginx 13: Permission denied 解决方案

    下面是详解Nginx 13: Permission denied 解决方案的完整攻略。 问题描述 在使用Nginx过程中,有时候我们会遇到这样的报错:Permission denied,一般来说,这种错误出现的原因有很多种,例如: Nginx服务器没有足够的权限来操作相关文件或目录。 Nginx用户没有被设置为文件或目录的所有者或组。 SELinux等安全策…

    Vue 2023年5月28日
    00
  • Vue项目代码之路由拆分、Vuex模块拆分、element按需加载详解

    我来为你详细讲解“Vue项目代码之路由拆分、Vuex模块拆分、element按需加载详解”的完整攻略。 路由拆分 当我们的项目变得越来越复杂时,路由也会变得越来越庞大。为了更好地维护我们的代码,我们可以考虑将路由进行拆分。 首先,我们可以在项目根目录下新建一个router文件夹,用来存放路由相关的文件。接着,我们可以在这个文件夹下新建一个index.js文件…

    Vue 2023年5月27日
    00
  • uniapp微信小程序无法获取Vue.prototype值的解决方法

    问题描述: 在使用uniapp框架开发微信小程序时,有时候会遇到Vue.prototype里放的值无法在小程序里获取的问题,这是因为uniapp的小程序使用的是微信原生小程序的组件库,因此Vue.prototype的值无法直接引入到小程序里。但是我们可以通过一些方法绕过这个问题。 解决方法: 在uniapp中引入wx对象,使用wx.$vm来代替Vue.pro…

    Vue 2023年5月27日
    00
  • vue-router路由懒加载及实现的3种方式

    接下来我会针对“vue-router路由懒加载及实现的3种方式”进行详细讲解。整个过程分为以下几个步骤: 路由懒加载是什么? 路由懒加载是指延迟加载路由组件,当组件被访问时才会加载该组件,而不是一次性加载所有组件。 为什么要使用路由懒加载? 使用路由懒加载可以提升页面的加载速度,特别是在项目较大、组件较多的情况下,可以大幅减少首屏加载时间,提升用户体验。 实…

    Vue 2023年5月28日
    00
  • 京东 Vue3 组件库支持小程序开发的详细流程

    以下是详细讲解“京东 Vue3 组件库支持小程序开发的详细流程”的完整攻略: 1. 准备工作 在开始开发之前,需要先准备好以下工作: 首先安装 Node.js (大于v10.13)和 yarn。 新建一个 Vue3 项目,使用 Vue CLI 搭建,并且安装好小程序开发的相关依赖。 2. 下载并安装组件库 京东 Vue3 组件库已经支持小程序开发,我们可以直…

    Vue 2023年5月27日
    00
  • vue2组件进阶与插槽详解(推荐!)

    Vue2组件进阶与插槽详解 本篇攻略主要介绍Vue2组件的一些进阶用法,重点讲解Vue2插槽的使用。 组件进阶 动态和异步组件 在实际应用中,有些组件只有在需要的时候才会被加载。Vue2提供两种方式达到这种效果:动态组件和异步组件。 动态组件 动态组件可以通过<component>标签来实现,需要指定is属性,该属性值对应动态组件加载的名称: &…

    Vue 2023年5月28日
    00
  • vscode中的vue项目报错Property ‘xxx‘ does not exist on type ‘CombinedVueInstance<{ readyOnly…Vetur(2339)

    在Vscode中开发Vue项目时,可能会遇到如下错误提示:Property ‘xxx’ does not exist on type ‘CombinedVueInstance<{ readyOnly: false; }, {}, {}, {}, Readonly<Record<…”,这种错误提示一般是类型检查导致的。 解决该问题的方法如下:…

    Vue 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部