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

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日

相关文章

  • vue3父组件和子组件如何传值实例详解

    当一个Vue应用程序变得越来越庞大时,其组件数也会逐渐增加。在这些组件中,父组件通常会传递数据给它们的子组件,以便子组件可以使用这些数据。 在Vue 3中,父组件通过两种方式向子组件传递数据: props和slots。下面我们来详细讲解这两种传值方式。 Props传值 父组件通过props向子组件传递数据。子组件可以在模板中使用这些数据,或者在脚本中通过实例…

    Vue 2023年5月28日
    00
  • vue forEach循环数组拿到自己想要的数据方法

    我来为您详细讲解vue forEach循环数组拿到自己想要的数据方法的完整攻略。 内容概述 什么是forEach循环 forEach方法与for循环的区别 遍历普通数组获取数据 遍历对象数组获取数据 示例说明 什么是forEach循环 forEach是一个数组方法,它会遍历数组中的每一个元素,并对其执行指定的回调函数。它可以替代常用的for循环,在遍历数组的…

    Vue 2023年5月29日
    00
  • VUE中使用HTTP库Axios方法详解

    下面我将为你详细讲解“VUE中使用HTTP库Axios方法详解”的完整攻略。 简介 Axios是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。它能够从服务器获取数据,也能将数据发送到服务器。Axios 支持各种请求方式,如 GET、POST、PUT、DELETE、HEAD 等。 在 Vue.js 项目中,我们可以通过 ax…

    Vue 2023年5月28日
    00
  • 解决Element中el-date-picker组件不回填的情况

    问题背景:Element UI 中 el-date-picker 组件在使用时有可能出现选择日期后无法回填的情况,即选择的日期无法正确显示在输入框中。这种情况出现的原因是由于用户未绑定 v-model 或者 v-model 绑定的变量内容不正确导致。 解决方案:由于该问题可能是由多方面问题引起的,此文将从以下几个方面详细讲解如何解决这个问题。 确认 v-mo…

    Vue 2023年5月29日
    00
  • vue学习之Vue-Router用法实例分析

    Vue-Router 是 Vue.js 官方的路由插件,它和 Vue.js 具有相同的核心思想,即都是将 UI 和行为抽象成组件的形式,且都支持通过 props 向子组件传递数据。 Vue-Router 可以让我们通过 URL 和组件的映射关系来实现页面的跳转和切换,同时还支持路由的嵌套、命名视图、多种路由参数传递方式等功能,非常强大和灵活。 下面我们来分析…

    Vue 2023年5月27日
    00
  • vue使用ajax获取后台数据进行显示的示例

    使用 Vue.js 进行前端开发时,常常需要从后端获取数据,并将其显示在页面上。其中一个常用的方式是通过 Ajax 技术向后端服务器发送 HTTP 请求,在得到响应后在前端页面上进行展示。下面是使用 Vue.js 实现向后端服务器发送 Ajax 请求并将其返回结果显示在页面上的示例攻略。 1. 在 Vue.js 中使用 Ajax Vue.js 提供了内置的 …

    Vue 2023年5月28日
    00
  • vue data中的return使用方法示例

    下面我将为您讲解“Vue data中的return使用方法示例”的完整攻略。 1. Vue data中的return使用方法介绍 在Vue框架中,我们经常会用到data属性来存放组件中需要用到的数据。而在Vue的data中,我们可以使用return来返回一个对象或者函数,用于存放数据。 下面是一个基本的使用示例: data() { return { mess…

    Vue 2023年5月28日
    00
  • vue后端传文件流转化成blob对象,前端点击下载返回undefined问题

    首先,问题的原因是因为没有正确获取服务端传回的文件流,导致在前端的blob对象中无法处理正确的文件数据。此时,我们需要采用axios响应拦截器的方式进行解决。 步骤如下: 步骤一:后端返回流数据 在后端返回的接口中,返回的数据应为二进制流,如下示例: @GetMapping("/download") public ResponseEnti…

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