前端 | 设计模式之 观察者模式&发布订阅模式

在前端开发中,观察者模式(Observer Pattern)发布订阅模式(Publish-Subscribe Pattern) 是两个重要的设计模式,广泛用于事件处理、状态管理等场景。虽然它们有相似之处,但本质上却有区别。

本文将详细解析这两种模式,包括它们的原理、区别、优缺点以及实现方式。

一、观察者模式

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会收到通知。

例如生活中,我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸。报社和订报纸的客户就形成了一对多的依赖关系

1. 核心结构

  • 观察者(Observer):订阅目标的对象,负责响应目标的通知。
  • 目标(Subject):被观察的对象,当状态发生变化时通知所有观察者。

2. 代码实现

// 目标类(被观察对象)
class Subject {
  constructor() {
    this.observers = []; // 存储观察者
  }

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

  // 移除观察者
  removeObserver(observer) {
    this.observers = this.observers.filter((obs) => obs !== observer);
  }

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

// 观察者类
class Observer {
  constructor(name) {
    this.name = name;
  }

  // 收到通知时执行的方法
  update(data) {
    console.log(`${this.name} received data:`, data);
  }
}

// 测试
const subject = new Subject();
const observer1 = new Observer("Observer 1");
const observer2 = new Observer("Observer 2");

subject.addObserver(observer1);
subject.addObserver(observer2);

subject.notify("Hello Observers!"); 
// Observer 1 received data: Hello Observers!
// Observer 2 received data: Hello Observers!

上述代码中,观察者主动申请加入被观察者的列表,被观察者主动将观察者加入列表

3. 应用场景

  • 前端框架的响应式系统(如 Vue 的响应式数据)。
  • 事件监听(如 DOM 事件绑定)。
  • 实时数据更新(如股票价格、天气更新等)。

二、发布订阅模式

发布-订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在

同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者存在

1. 核心结构

  • 发布者(Publisher):发送消息。
  • 订阅者(Subscriber):接收消息。
  • 事件中心(Event Bus):管理订阅和发布的中间角色。

2. 代码实现

class PubSub {
  constructor() {
    this.messages = {};
    this.listeners = {};
  }
  // 添加发布者
  publish(type, content) {
    const existContent = this.messages[type];
    if (!existContent) {
      this.messages[type] = [];
    }
    this.messages[type].push(content);
  }
  // 添加订阅者
  subscribe(type, cb) {
    const existListener = this.listeners[type];
    if (!existListener) {
      this.listeners[type] = [];
    }
    this.listeners[type].push(cb);
  }
  // 通知
  notify(type) {
    const messages = this.messages[type];
    const subscribers = this.listeners[type] || [];
    subscribers.forEach((cb, index) => cb(messages[index]));
  }
}

发布者代码:

class Publisher {
  constructor(name, context) {
    this.name = name;
    this.context = context;
  }
  publish(type, content) {
    this.context.publish(type, content);
  }
}

订阅者代码:

class Subscriber {
  constructor(name, context) {
    this.name = name;
    this.context = context;
  }
  subscribe(type, cb) {
    this.context.subscribe(type, cb);
  }
}

使用:

const TYPE_A = 'music';
const TYPE_B = 'movie';
const TYPE_C = 'novel';

const pubsub = new PubSub();

const publisherA = new Publisher('publisherA', pubsub);
publisherA.publish(TYPE_A, 'we are young');
publisherA.publish(TYPE_B, 'the silicon valley');
const publisherB = new Publisher('publisherB', pubsub);
publisherB.publish(TYPE_A, 'stronger');
const publisherC = new Publisher('publisherC', pubsub);
publisherC.publish(TYPE_C, 'a brief history of time');

const subscriberA = new Subscriber('subscriberA', pubsub);
subscriberA.subscribe(TYPE_A, res => {
  console.log('subscriberA received', res)
});
const subscriberB = new Subscriber('subscriberB', pubsub);
subscriberB.subscribe(TYPE_C, res => {
  console.log('subscriberB received', res)
});
const subscriberC = new Subscriber('subscriberC', pubsub);
subscriberC.subscribe(TYPE_B, res => {
  console.log('subscriberC received', res)
});

pubsub.notify(TYPE_A);
pubsub.notify(TYPE_B);
pubsub.notify(TYPE_C);

上述代码中,发布者和订阅者需要通过发布订阅中心进行关联,发布者的发布动作和订阅者的订阅动作相互独立,无需关注对方,消息派发由发布订阅中心负责

3. 应用场景

  1. 事件总线:前端框架中的跨组件通信(如 Vue 的 EventBus)。
  2. 消息队列:系统中不同模块间的消息传递(如 RabbitMQ)。
  3. 模块解耦:将发布者和订阅者解耦,提升系统灵活性。

三、对比

对比点观察者模式发布订阅模式
中间人角色无事件中心,观察者直接订阅目标有事件中心,发布者与订阅者通过事件中心通信
关系类型一对多多对多
灵活性较低,观察者依赖于目标高,发布者和订阅者完全解耦
典型应用响应式数据、DOM事件监听跨组件通信、模块解耦

四、总结

  • 观察者模式 适用于直接的依赖关系,如响应式数据绑定。
  • 发布订阅模式 通过引入事件中心,适用于松耦合、多对多的场景,如跨模块通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值