观察者模式和发布订阅模式的区别

理解观察者模式和发布订阅模式的定义、实现和使用场景

问题

观察者模式和发布订阅模式分别是什么?它们有什么区别?

解答

观察者模式

观察者模式中,观察者直接订阅主题对象。当主题状态改变时,会直接通知所有观察者。

// 主题(被观察者)
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} 收到更新:`, data);
  }
}

// 使用
const subject = new Subject();
const observer1 = new Observer('观察者1');
const observer2 = new Observer('观察者2');

subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify('状态改变了');

发布订阅模式

发布订阅模式中,发布者和订阅者不直接通信,而是通过调度中心(事件中心)进行解耦。

// 调度中心(事件中心)
class EventBus {
  constructor() {
    this.events = {};
  }

  // 订阅事件
  subscribe(eventName, callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(callback);
  }

  // 发布事件
  publish(eventName, data) {
    if (this.events[eventName]) {
      this.events[eventName].forEach(callback => callback(data));
    }
  }

  // 取消订阅
  unsubscribe(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName] = this.events[eventName].filter(cb => cb !== callback);
    }
  }
}

// 使用
const eventBus = new EventBus();

// 订阅者1
eventBus.subscribe('userLogin', (data) => {
  console.log('订阅者1 收到登录事件:', data);
});

// 订阅者2
eventBus.subscribe('userLogin', (data) => {
  console.log('订阅者2 收到登录事件:', data);
});

// 发布者发布事件
eventBus.publish('userLogin', { username: 'Alice' });

主要区别

角色数量不同:观察者模式只有观察者和被观察者两个角色,它们直接通信。发布订阅模式有发布者、订阅者和调度中心三个角色,发布者和订阅者通过调度中心间接通信。

耦合程度不同:观察者模式中,主题和观察者相互知道对方的存在,耦合度较高。发布订阅模式中,发布者和订阅者完全解耦,互不知道对方的存在。

使用场景不同:观察者模式适合单个应用内部使用,比如 Vue 的响应式系统。发布订阅模式适合跨应用或跨模块的场景,比如 Node.js 的 EventEmitter、浏览器的事件系统。

关键点

  • 观察者模式是主题直接通知观察者,两者直接耦合
  • 发布订阅模式通过调度中心解耦发布者和订阅者
  • 观察者模式适合应用内部,发布订阅模式适合跨应用场景
  • 发布订阅模式更灵活,但增加了系统复杂度