JavaScript 如何实现观察者模式

在日常开发中,你有没有过这种经历:页面上的购物车商品数量变了,导航栏右上角的数字自动跟着更新;或者你订阅了某个公众号,一旦作者发新文章,你立刻能收到推送?其实这些场景背后,藏着一种很实用的设计模式——观察者模式。而 JavaScript 因为灵活的事件机制,实现这个模式特别简单。

什么是观察者模式?用生活例子秒懂

先别被“模式”两个字吓住,它本质就是“一对多的通知关系”。举个生活化的例子:小区里的快递驿站,会有很多住户来取快递。如果驿站给每个住户单独发消息说“你的快递到了”,不仅麻烦,还可能漏发;但换个方式,住户只要提前在驿站登记“我要接收快递通知”(订阅),驿站只要有新快递到,就给所有登记过的住户发消息(广播通知),没人会错过,也不用反复操作。

JavaScript 如何实现观察者模式

放到代码里,这个逻辑对应两个角色:

  • 观察者:就是那些“想要接收通知”的对象,比如住户;
  • 目标(被观察者):就是“提供通知的主体”,比如快递驿站。

目标会维护一个观察者列表,新增观察者(订阅)、移除观察者(退订),还能在自己状态变化时,遍历列表通知所有观察者。

JavaScript 实现观察者模式的核心步骤

在 JS 里,不用复杂的工具,用几个简单的方法就能搭出这个模式,我们用刚才的快递例子对应代码:

第一步:写一个“目标”类,管理观察者列表

目标类的核心是三个方法:添加观察者、移除观察者、通知所有观察者。我们给它起个名字叫 DeliveryStation(快递驿站):

`javascript

class DeliveryStation {

constructor() {

// 用数组存所有登记的住户(观察者)

this.observers = [];

}

// 订阅:把新住户加到列表里

subscribe(observer) {

this.observers.push(observer);

console.log(${observer.name} 成功订阅快递通知);

}

// 退订:把住户从列表里去掉

unsubscribe(observer) {

this.observers = this.observers.filter(item => item !== observer);

console.log(${observer.name} 已退订快递通知);

}

// 状态变化:有新快递到,通知所有观察者

notify(快递信息) {

this.observers.forEach(observer => {

observer.update(快递信息);

});

}

}

`

第二步:写一个“观察者”类,定义收到通知的反应

观察者的核心是一个 update 方法,用来处理收到通知后的动作。这里的观察者就是住户,比如小张、小李:

`javascript

class Resident {

constructor(name) {

this.name = name;

}

// 收到快递通知后的反应

update(快递信息) {

console.log(${this.name} 收到通知:${快递信息});

}

}

`

第三步:用起来,看看实际效果

现在把代码串起来,模拟一次快递到的场景:

`javascript

// 初始化驿站和住户

const station = new DeliveryStation();

const zhang = new Resident('小张');

const li = new Resident('小李');

// 小张和小李订阅通知

station.subscribe(zhang); // 输出:小张成功订阅快递通知

station.subscribe(li); // 输出:小李成功订阅快递通知

// 驿站有新快递到,发通知

station.notify('您的快递(取件码1234)已送达驿站');

// 输出:小张收到通知:您的快递(取件码1234)已送达驿站

// 输出:小李收到通知:您的快递(取件码1234)已送达驿站

// 小张退订,再发通知试试

station.unsubscribe(zhang); // 输出:小张已退订快递通知

station.notify('您的另一个快递(取件码5678)已送达驿站');

// 输出:小李收到通知:您的另一个快递(取件码5678)已送达驿站

`

你看,小张退订后就再也收不到通知了,完全符合我们的需求。

实际开发里的常见用法

可能有人会问,这种模式在真实项目里用在哪?比如你做一个待办事项列表,新增一个待办时,不仅要显示在列表里,还要统计“待办数量”更新到页面角落;或者做一个主题切换功能,用户选了深色模式,页面的所有按钮、背景都要自动变成深色——这些场景里,“待办列表”“主题切换器”就是被观察者,“列表渲染器”“页面元素”就是观察者,用观察者模式能把代码拆得更清晰,不用写一堆重复的逻辑。

而且 JS 里其实有现成的简化方案,比如用 EventTarget 类,或者第三方库像 RxJS,能处理更复杂的异步通知,但核心逻辑还是我们刚才说的“订阅-通知”的一对多关系。

上一篇 Java 线程怎么创建