观察者设计模式在Js中的使用

观察者设计模式

定义

一种行为型设计模式,用于在对象之间建立一种一对多的依赖关系 ,当一个对象的状态发生变化 时,它的所有依赖对象 都会收到通知并自动更新

参与者

<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{red}{1.} </math>1. 主题 (Subject):也称为被观察者或可观察对象 ,它维护 着一组观察者对象,并提供了添加、删除和通知观察者的方法。主题可以是具体的类或接口。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{red}{2.} </math>2. 观察者 (Observer):也称为订阅者,它定义了接收和处理主题通知的方法 。观察者通过注册到主题上来接收通知,并根据通知进行相应的操作。观察者可以是具体的类或接口。

在观察者设计模式中,主题和观察者之间是松耦合的关系。主题并不直接调用观察者的方法,而是通过通知的方式告知观察者发生了变化。观察者通过注册到主题上来表明自己感兴趣的事件,并在事件发生时接收到通知。

核心思想

解耦发布者订阅者 ,使得两者之间能够独立变化 。当一个对象的状态发生变化时,所有依赖于它的观察者都会得到通知,并自动更新以反映最新的状态。

应用场景

  • GUI 事件处理 :图形用户界面(GUI)中的按钮、菜单项和其他控件通常作为主题,可以被不同的观察者订阅,以响应用户的交互操作。
  • 消息队列系统 :在消息队列系统中,生产者 发送消息到主题,而消费者作为观察者订阅主题来接收和处理消息。
  • 数据库通知机制 :数据库中的触发器事件通知机制 可以使用观察者模式来实现。触发器可以充当主题,而订阅该触发器的存储过程或应用程序可以作为观察者进行相应的处理。
  • 股票市场更新 :股票市场中的投资者 可以作为观察者订阅特定股票的主题,以接收价格更新的通知。

示例

typescript 复制代码
// 主题接口
interface Subject {
  registerObserver(observer: Observer): void;
  removeObserver(observer: Observer): void;
  notifyObservers(): void;
}

// 观察者接口
interface Observer {
  update(data: any): void;
}

// 具体主题类
class ConcreteSubject implements Subject {
  private observers: Observer[] = [];
  private data: any;

  registerObserver(observer: Observer): void {
    this.observers.push(observer);
  }

  removeObserver(observer: Observer): void {
    const index = this.observers.indexOf(observer);
    if (index !== -1) {
      this.observers.splice(index, 1);
    }
  }

  notifyObservers(): void {
    for (const observer of this.observers) {
      observer.update(this.data);
    }
  }

  setData(data: any): void {
    this.data = data;
    this.notifyObservers();
  }
}

// 具体观察者类
class ConcreteObserver implements Observer {
  private name: string;

  constructor(name: string) {
    this.name = name;
  }

  update(data: any): void {
    console.log(`Observer ${this.name} received data: ${data}`);
  }
}

// 客户端代码
const subject = new ConcreteSubject();

const observer1 = new ConcreteObserver("Observer 1");
const observer2 = new ConcreteObserver("Observer 2");

subject.registerObserver(observer1);
subject.registerObserver(observer2);

subject.setData("Hello world!");

前端应用

<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{red}{1.} </math>1. 事件处理 :在 JavaScript 和浏览器中,事件机制就是观察者设计模式的实现DOM 元素 可以作为主题 ,而事件监听函数 则充当观察者。当事件发生时,主题会通知所有注册的观察者执行相应的事件处理函数。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{red}{2.} </math>2. AJAX 请求 :在使用 XMLHttpRequest 或 Fetch API 发起 AJAX 请求时,我们可以将请求对象 作为主题 ,而回调函数 作为观察者。当请求返回结果时,主题会通知观察者进行相应的处理。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{red}{3.} </math>3. 订阅-发布(Pub/Sub)模式:该模式是观察者模式的一种变体,在 JavaScript 中被广泛应用于消息传递和事件系统。通过订阅和发布机制,多个订阅者可以同时订阅特定的主题,并在主题发生变化时接收通知。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 4. \color{red}{4.} </math>4. 数据绑定和响应式框架 :许多前端框架和库,如 Vue.js 和 React.js ,使用观察者模式来实现数据绑定和响应式更新。当数据发生变化时,框架会通知相关的观察者组件,使其自动更新视图。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 5. \color{red}{5.} </math>5. WebSocket 通信 :WebSocket 是一种双向通信协议,利用观察者模式来实现实时消息推送。服务器 可以作为主题 ,而客户端 则充当观察者。当服务器有新消息时,它会通知所有连接的客户端。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 6. \color{red}{6.} </math>6. Node.js 事件驱动编程 :Node.js 是基于事件驱动的非阻塞 I/O 模型。它使用观察者模式来处理事件回调函数。当特定的事件发生时,Node.js 会通知相应的观察者执行对应的回调函数,以实现异步和并发操作。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 7. \color{red}{7.} </math>7. 第三方库 :MobX 是一个 JavaScript 库,用于管理状态(state)和处理状态变化。它使用了观察者模式来跟踪对状态 的更改,并使得相关组件能够自动地进行更新。

ES6 Observers

ES6 中引入了五种 Observer,可以看成是对订阅者模式的实践,它们分别为:

<math xmlns="http://www.w3.org/1998/Math/MathML"> 1. \color{red}{1.} </math>1. ResizeObserver:用于监测元素尺寸变化。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 2. \color{red}{2.} </math>2. MutationObserver:用于监测 DOM 树的变化。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 3. \color{red}{3.} </math>3. ReportingObserver:用于监测报告类型的变化。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 4. \color{red}{4.} </math>4. PerformanceObserver:用于监测页面性能指标。

<math xmlns="http://www.w3.org/1998/Math/MathML"> 5. \color{red}{5.} </math>5. IntersectionObserver:用于监测元素是否进入视口或与其交叉。

对于上面的这五个 Observer 的使用,我会在下一篇文章中介绍!

相关推荐
尘中客4 小时前
放弃 Echarts?前端直接渲染后端高精度 SVG 矢量图流的踩坑记录
前端·javascript·echarts·前端开发·svg矢量图·echarts避坑
FreeBuf_4 小时前
Chrome 0Day漏洞遭野外利用
前端·chrome
小彭努力中5 小时前
199.Vue3 + OpenLayers 实现:点击 / 拖动地图播放音频
前端·vue.js·音视频·openlayers·animate
2501_916007475 小时前
网站爬虫原理,基于浏览器点击行为还原可接口请求
前端·javascript·爬虫·ios·小程序·uni-app·iphone
前端大波5 小时前
Sentry 每日错误巡检自动化:设计思路与上手实战
前端·自动化·sentry
Highcharts.js6 小时前
适合报表系统的可视化图表|Highcharts支持直接导出PNG和PDF
javascript·数据库·react.js·pdf
ZC跨境爬虫6 小时前
使用Claude Code开发校园交友平台前端UI全记录(含架构、坑点、登录逻辑及算法)
前端·ui·架构
慧一居士6 小时前
Vue项目中,何时使用布局、子组件嵌套、插槽 对应的使用场景,和完整的使用示例
前端·vue.js
叫我一声阿雷吧6 小时前
JS 入门通关手册(35):执行上下文、调用栈与作用域链深度解析
javascript·作用域链·js进阶·执行上下文·调用栈·变量提升·闭包原理
Можно6 小时前
uni.request 和 axios 的区别?前端请求库全面对比
前端·uni-app