JavaScript如何实现观察者模式_它和发布订阅模式有何不同

16次阅读

观察者模式与发布-订阅模式本质区别在于耦合度与通信方式:前者是主体与观察者直接同步调用,后者通过事件总线异步解耦通信。

JavaScript如何实现观察者模式_它和发布订阅模式有何不同

javaScript 中观察者模式和发布-订阅模式常被混淆,但二者在结构、依赖关系和通信方式上有本质区别。观察者模式强调“一对多”的同步依赖,目标对象(Subject)直接持有观察者(Observer)的引用;而发布-订阅模式通过“事件总线”解耦双方,依赖中介(Event Bus)完成异步消息分发。

观察者模式:主体与观察者直接关联

观察者模式中,被观察的目标(Subject)维护一个观察者列表,当状态变化时,主动遍历并调用每个观察者的更新方法。观察者需显式订阅(attach)和退订(detach),且必须了解 Subject 的存在。

典型实现要点:

  • Subject 提供 addObserverremoveObservernotify 方法
  • Observer 实现统一的 update 接口(或回调函数
  • Subject 与 Observer 是强引用关系,生命周期易耦合
  • 通知是同步的,执行顺序即注册顺序

例如:dom 事件监听本质上是观察者模式的变体——元素(Subject)持有事件处理函数(Observer)的引用,触发 click 时同步调用 handler。

立即学习Java免费学习笔记(深入)”;

发布-订阅模式:靠事件中心解耦通信

发布-订阅模式引入第三方“事件总线”(Event Bus 或 PubSub),发布者(Publisher)只向总线发消息,订阅者(Subscriber)只向总线注册回调。双方互不知晓,也不持有对方引用。

关键特征:

  • 总线提供 on(订阅)、off(取消)、emit(发布)方法
  • 支持按事件类型(如 “user:login”)过滤,可一对多、多对多、甚至零对多
  • 消息可缓存、延迟派发,支持异步、队列、中间件等扩展
  • 天然支持跨组件、跨模块通信,常见于 vue 的 $bus、node.js 的 EventEmitter

核心差异对比

二者最根本的不同在于耦合程度与通信路径

  • 依赖关系:观察者模式中 Observer 知道 Subject,Subject 也持有 Observer;发布-订阅中 Publisher 和 Subscriber 都只依赖 Event Bus
  • 通信方式:观察者是同步、即时、点对点的;发布-订阅是异步、事件驱动、基于主题(topic)的间接通信
  • 灵活性:发布-订阅支持动态事件名、通配符匹配(如 “user:*”)、优先级、once 订阅等,观察者模式通常固定在单一状态变更上
  • 内存管理:观察者若忘记 detach 易导致内存泄漏;发布-订阅虽也需 off,但总线可提供自动清理策略(如组件销毁时批量清除)

简单代码示意

观察者模式简写:

class Subject {   constructor() { this.observers = []; }   addObserver(o) { this.observers.push(o); }   notify(data) { this.observers.forEach(o => o.update(data)); } } class Observer { update(data) { console.log('Received:', data); } }

发布-订阅简写:

class EventBus {   constructor() { this.events = {}; }   on(type, fn) { (this.events[type] = this.events[type] || []).push(fn); }   emit(type, data) { this.events[type]?.forEach(fn => fn(data)); } }

注意:实际项目中推荐使用成熟的库(如 mitt、tiny-emitter)或框架内置机制(react 的 Context + usereducer、Vue 的 provide/inject + emits),避免手写总线带来的边界问题。

text=ZqhQzanResources