观察者模式实例

用生活场景理解观察者模式并实现

问题

用生活中的例子解释观察者模式,并用代码实现。

解答

生活场景:微信公众号

观察者模式就像订阅公众号:

  • 公众号是被观察者(Subject)
  • 订阅者是观察者(Observer)
  • 公众号发文时,所有订阅者都会收到通知

代码实现

// 被观察者:公众号
class WeChatAccount {
  constructor(name) {
    this.name = name
    this.subscribers = [] // 订阅者列表
  }

  // 添加订阅者
  subscribe(observer) {
    if (!this.subscribers.includes(observer)) {
      this.subscribers.push(observer)
      console.log(`${observer.name} 订阅了 ${this.name}`)
    }
  }

  // 取消订阅
  unsubscribe(observer) {
    const index = this.subscribers.indexOf(observer)
    if (index > -1) {
      this.subscribers.splice(index, 1)
      console.log(`${observer.name} 取消订阅 ${this.name}`)
    }
  }

  // 发布文章,通知所有订阅者
  publish(article) {
    console.log(`\n${this.name} 发布了: ${article}`)
    this.subscribers.forEach(observer => {
      observer.update(this.name, article)
    })
  }
}

// 观察者:订阅者
class Subscriber {
  constructor(name) {
    this.name = name
  }

  // 收到通知时的处理
  update(accountName, article) {
    console.log(`${this.name} 收到 ${accountName} 的推送: ${article}`)
  }
}

// 使用示例
const techAccount = new WeChatAccount('前端早读课')

const zhangsan = new Subscriber('张三')
const lisi = new Subscriber('李四')
const wangwu = new Subscriber('王五')

// 订阅
techAccount.subscribe(zhangsan)
techAccount.subscribe(lisi)
techAccount.subscribe(wangwu)

// 发布文章
techAccount.publish('JavaScript 闭包解析')

// 李四取消订阅
techAccount.unsubscribe(lisi)

// 再次发布
techAccount.publish('Promise 使用技巧')

输出结果:

张三 订阅了 前端早读课
李四 订阅了 前端早读课
王五 订阅了 前端早读课

前端早读课 发布了: JavaScript 闭包解析
张三 收到 前端早读课 的推送: JavaScript 闭包解析
李四 收到 前端早读课 的推送: JavaScript 闭包解析
王五 收到 前端早读课 的推送: JavaScript 闭包解析
李四 取消订阅 前端早读课

前端早读课 发布了: Promise 使用技巧
张三 收到 前端早读课 的推送: Promise 使用技巧
王五 收到 前端早读课 的推送: Promise 使用技巧

其他生活实例

场景被观察者观察者
红绿灯交通灯行人、车辆
拍卖会拍卖师竞拍者
股票股价股民
外卖订单状态顾客

关键点

  • 一对多关系:一个被观察者对应多个观察者
  • 松耦合:被观察者不需要知道观察者的具体实现
  • 主动推送:状态变化时自动通知,观察者无需轮询
  • DOM 事件就是观察者模式addEventListener 添加观察者,事件触发时通知
  • 与发布订阅的区别:观察者模式是直接通知,发布订阅有中间的事件中心