JS设计模式(4):观察者模式

发布于:2025-06-07 ⋅ 阅读:(15) ⋅ 点赞:(0)

JS设计模式(4):观察者模式

一、引入

在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如:

  • 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;
  • 新闻网站中,发布新新闻时需要推送给所有订阅该频道的读者;
  • 股票行情系统中,股票价格变动时需要实时通知所有关注该股票的投资者。

这些场景的共同特点是:多个对象之间存在依赖关系,一个对象的状态改变会影响到其他对象。如果直接在代码中硬编码这些依赖关系,会导致代码耦合度高、难以维护和扩展。此时,观察者模式(Observer Pattern)就能很好地解决这类问题。

读完本文,你将学会如何利用观察者模式实现对象间的消息通信,让代码在保持低耦合的同时,具备更强的可维护性和扩展性。

二、何为观察者模式

观察者模式是一种行为型设计模式,其核心思想是:定义对象间的一种一对多依赖关系,使得当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都能自动收到通知并执行相应的操作。

核心角色

  • 被观察者(Subject):维护观察者列表,提供添加、删除观察者的方法,当状态变化时通知所有观察者。
  • 观察者(Observer):定义接收通知的接口,通常包含一个更新方法,用于在收到通知时执行具体操作。

实现思路
通过Proxy代理对象实现数据劫持,当被观察对象的属性发生变化时,自动触发通知逻辑,通知所有注册的观察者。

三、代码实现

我们以一个简单的人物信息对象为例,演示观察者模式的具体实现:

// 原始数据对象
const person = {
  name: 'ts',
  age: 21
}

// 被观察者类
class Subject {
  constructor(value) {
    this.observers = []; // 存储观察者列表
    // 使用Proxy实现数据代理,监听属性变化
    const handler = {
      get: (self, key) => {
        return self[key];
      },
      set: (self, key, newVal) => {
        // 打印属性变化信息
        console.log(`${key}${self[key]}修改为${newVal}`);
        // 触发通知
        this.notify(key, newVal);
        self[key] = newVal; // 更新属性值
        return true;
      }
    };
    this.value = new Proxy(value, handler); // 生成代理对象
  }

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

  // 通知所有观察者
  notify(key, newVal) {
    this.observers.forEach(observer => observer.update(key, newVal));
  }
}

// 观察者类
class Observer {
  constructor(value) {
    this.value = value; // 观察者自身的数据
  }

  // 更新方法,收到通知时执行
  update(key, value) {
    console.log(`${this.value.name}观察到${key}变化了,新的值是${value}`);
    this.value[key] = value; // 更新观察者自身的数据
  }
}

// 创建被观察者实例,传入原始数据
const proxyPerson = new Subject(person);

// 创建观察者实例
const obs1 = new Observer({ name: 'xll', age: 100 });
const obs2 = new Observer({ name: 'xhh', age: 3 });

// 注册观察者
proxyPerson.add(obs1);
proxyPerson.add(obs2);

// 修改被观察对象的属性,触发通知
proxyPerson.value.age = 10;
proxyPerson.value.name = 'js';

执行结果

age从21修改为10
xll观察到age变化了,新的值是10
xhh观察到age变化了,新的值是10
name从ts修改为js
xll观察到name变化了,新的值是js
xhh观察到name变化了,新的值是js

四、代码解析

  1. 被观察者(Subject)

    • 通过Proxy对原始数据对象进行代理,重写getset方法,实现对属性访问和修改的拦截。
    • 当属性被修改时,调用notify方法通知所有观察者。
    • add方法用于注册观察者,将观察者添加到观察者列表中。
  2. 观察者(Observer)

    • 每个观察者都有自己的状态数据(如obs1obs2nameage)。
    • update方法是观察者的核心逻辑,用于在收到通知时更新自身状态,并执行相应的业务操作(如打印日志)。
  3. 解耦与通知流程

    • 被观察者和观察者之间通过接口进行通信,彼此无需知道对方的具体实现,实现了低耦合。
    • 当被观察对象的属性发生变化时,通过Proxy自动触发通知,观察者被动接收通知并更新状态,形成了“数据变化→通知→更新”的完整流程。

五、观察者模式的优点

维度 观察者模式 直接调用方式
耦合性 低耦合,对象间无需直接依赖 高耦合,对象间直接调用
扩展性 新增观察者无需修改被观察者 新增功能需修改原始代码
复用性 观察者可复用于多个被观察者 功能复用性差
灵活性 可动态添加/删除观察者 功能绑定固定,难以调整

六、应用场景

  • 状态监控:监控服务器状态、设备状态等,当状态变化时通知相关系统或人员。
  • 消息订阅:实现消息发布-订阅系统,如邮件订阅、短信通知等。
  • 数据绑定:前端框架中的数据双向绑定(如Vue的响应式原理),本质上就是观察者模式的应用。
  • 事件驱动:浏览器中的事件监听(如点击事件、键盘事件等),也是观察者模式的典型场景。

通过观察者模式,我们可以将对象间的依赖关系从紧耦合变为松耦合,使系统更具灵活性和可扩展性。在后续的文章中,我们将继续探讨其他设计模式,帮助你写出更优雅、更易维护的代码。如果你有任何问题或建议,欢迎在评论区留言!


网站公告

今日签到

点亮在社区的每一天
去签到