For AI agents: the complete documentation index is at llms.txt. Markdown versions of any page are available by appending .md to the URL path.

学习观察者模式

设计模式Design Patterns

观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个 “观察” 该对象的对象。

什么是观察者模式

观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个 “观察” 该对象的对象。

有值得关注的状态的对象通常被称为目标,由于它要将自身的状态改变通知给其他对象,我们也将其称为发布者 (publisher),所有希望关注发布者状态变化的其他对象被称为订阅者(subscribers)。

当发布者发布了事件,它要遍历订阅者并调用其对象的特定通知方法。

举例说明观察者模式类似于明星与粉丝的关系,粉丝关注明星,当明星发布消息的时候,粉丝会对这个消息做出反应。

观察者模式适用场景

当一个对象状态的改变需要改变其他对象,可使用观察者模式。

当一些对象必须观察其他对象时,可使用观察者模式。

实现观察者模式

// 目标
class Subject {
  constructor() {
    this.observers = []
  }

  // 添加观察者
  attach(observer) {
    const isExist = this.observers.includes(observer)

    if (isExist) {
      console.log('观察者已添加')
      return
    }

    this.observers.push(observer)
  }

  // 移除观察者
  detach(observer) {
    const index = this.observers.indexOf(observer)

    if (index < 0) {
      console.log('观察者不存在')
      return
    }

    this.observers.splice(index, 1)
  }

  // 通知观察者
  notify() {
    for (const observer of this.observers) {
      observer.update(this)
    }
  }
}

// 观察者
class Observer {
  // 接收发布事件
  update(subject) {}
}

一个例子

小明,小红,小安都会留意早餐吃什么,不同的早餐会使他们产生不同的情绪,因此早餐是目标,三人是观察者。

// 继承目标类
class Breakfast extends Subject {
  constructor(element) {
    super()
    this.value = ''
    this.element = element

    this.element.addEventListener('change', (event) => {
      this.value = this.element.value
      this.notify()
    })
  }

  notify() {
    for (const observer of this.observers) {
      observer.update(this.value)
    }
  }
}

// 继承观察者类
class Person extends Observer {
  constructor(element) {
    super()
    this.mood = ''
    this.element = element
  }

  update(subject) {}
}

// 类型一
class Person1 extends Person {
  update(value) {
    switch (value) {
      case 'bread':
        this.mood = '开心'
        break
      case 'noodles':
        this.mood = '喜悦'
        break
      case 'gruel':
        this.mood = '讨厌'
        break
      default:
        this.mood = ''
        break
    }
    this.element.querySelector('.mood').innerHTML = this.mood
  }
}

// 类型二
class Person2 extends Person {
  update(value) {
    switch (value) {
      case 'bread':
        this.mood = '讨厌'
        break
      case 'noodles':
        this.mood = '开心'
        break
      case 'gruel':
        this.mood = '还可以'
        break
      default:
        this.mood = ''
        break
    }
    this.element.querySelector('.mood').innerHTML = this.mood
  }
}

// 类型三
class Person3 extends Person {
  update(value) {
    switch (value) {
      case 'bread':
        this.mood = '不喜欢'
        break
      case 'noodles':
        this.mood = '还可以'
        break
      case 'gruel':
        this.mood = '开心'
        break
      default:
        this.mood = ''
        break
    }
    this.element.querySelector('.mood').innerHTML = this.mood
  }
}

// 创建目标“早餐”
const breakfast = new Breakfast(document.getElementById('breakfast'))
// 创建观察者小明
const xiaoming = new Person1(document.getElementById('xiaoming'))
// 创建观察者小红
const xiaohong = new Person2(document.getElementById('xiaohong'))
// 创建观察者小安
const xiaoan = new Person3(document.getElementById('xiaoan'))

// 添加观察者
breakfast.attach(xiaoming)
breakfast.attach(xiaohong)
breakfast.attach(xiaoan)

// 取消观察
// breakfast.detach(xiaoan)

当早餐发生变化时,不同类型的人会根据不同的早餐产生不同的情绪。

breakfrast

See the Pen Observer Pattern by Cold Stone (@xrr2016) on CodePen.