IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    JavaScript - 观察者与发布订阅者模式

    发表于 2022-07-01 00:00:00
    love 0

    观察者模式

    • 观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有 依赖者 都会收到通知并自动更新。
    • 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
    • 可以看作 拍卖场景 ,拍卖师观察最高标价,然后通知给其他竞价者竞价。

    优点:

    • 观察者和被观察者是抽象耦合的,实现简单,主题和观察者之间的关系明确,适用于一对多的关系。

    缺点:

    • 当观察者较多时,主题的通知机制可能会导致性能问题,因为每个观察者都会被直接通知。

    具体实现

    class Observer {
      constructor(name) {
        this.name = name
      }
      update(data) {
        console.log(`观察者${this.name} 收到了: ${data}`)
      }
    }
    
    class Subject {
      constructor() {
        this.observers = []
      }
      add(observer) {
        this.observers.push(observer)
      }
      notify(data) {
        this.observers.forEach((i) => i.update(data))
      }
      delete(observer) {
        this.observers = this.observers.filter((i) => i !== observer)
      }
    }
    

    具体使用

    const sub = new Subject()
    const observer1 = new Observer('A')
    const observer2 = new Observer('B')
    sub.add(observer1)
    sub.add(observer2)
    
    sub.notify('一条新闻')
    // 观察者A 收到了: 一条新闻
    // 观察者B 收到了: 一条新闻
    
    sub.notify('今天的天气是晴天')
    // 观察者A 收到了: 今天的天气是晴天
    // 观察者B 收到了: 今天的天气是晴天
    
    sub.delete(observer1)
    

    发布订阅者模式

    • 发布/订阅(Publish–subscribe pattern)是一种消息范式,消息的 发送者 (称为发布者)不会将消息直接发送给特定的 接收者 (称为订阅者)。
    • 而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。
    • 可以看作一个为 邮件系统 ,你可以作为 订阅者 订阅某个网站的通知,邮件系统在其中充当 发布订阅中心 的角色,而 发布者 则是你订阅的网站。

    优点:

    • 解耦发布者和订阅者,使得系统更灵活,扩展性更好;支持多对多的关系,可以实现更复杂的消息通信。

    缺点:

    • 引入了调度中心,可能会增加系统的复杂度;由于间接通信,调试和理解代码可能会稍微困难一些。

    具体实现

    class Dep {
      constructor() {
        this.subscriptions = {}
      }
    
      subscribe(topic, callback) {
        if (!this.subscriptions[topic]) {
          this.subscriptions[topic] = []
        }
        this.subscriptions[topic].push(callback)
      }
    
      unSubscribe(topic) {
        if (!this.subscriptions[topic]) {
          return
        }
        delete this.subscriptions[topic]
      }
    
      publish(topic, data) {
        if (!this.subscriptions[topic]) {
          return
        }
        this.subscriptions[topic].forEach((callback) => {
          callback(data)
        })
      }
    }
    
    class Publisher {
      constructor(pub) {
        this.pub = pub
      }
    
      publishMessage(topic, message) {
        this.pub.publish(topic, message)
      }
    }
    
    class Subscriber {
      constructor(sub, name) {
        this.sub = sub
        this.name = name
      }
    
      subscribeToTopic(topic) {
        this.sub.subscribe(topic, (data) => {
          console.log(`订阅者 ${this.name} 收到${topic}消息: ${data}`)
        })
      }
    
      unSubscribeToTopic(topic) {
        this.sub.unSubscribe(topic, (data) => {
          console.log(`订阅者 ${this.name} 取消订阅${topic}消息: ${data}`)
        })
      }
    }
    

    具体使用

    const dep = new Dep()
    const publisher = new Publisher(dep)
    
    const subscriber1 = new Subscriber(dep, 'A')
    const subscriber2 = new Subscriber(dep, 'B')
    
    subscriber1.subscribeToTopic('news')
    subscriber2.subscribeToTopic('weather')
    
    publisher.publishMessage('news', '一条新闻')
    // 订阅者 A 收到news消息: 一条新闻
    
    publisher.publishMessage('weather', '今天的天气是晴天')
    // 订阅者 B 收到weather消息: 今天的天气是晴天
    
    subscriber1.unSubscribeToTopic('news')
    


沪ICP备19023445号-2号
友情链接