Skip to content

发布订阅和观察者

观察者模式(Observer Pattern)

观察者模式是一种行为型模式,允许对象(观察者)订阅另一个对象(被观察者)的状态变化,当被观察者的状态发生变化时,会通知所有订阅了它的观察者

核心概念:观察者和被观察者之间是一对多的关系,观察者直接依赖于被观察者,并在被观察者发生变化时自动更新

通信方向:单向通信,被观察者主动通知观察者,观察者被动接收

特点:

  • 观察者与被观察者是紧耦合的,被观察者会直接持有观察者的引用。

  • 观察者需要主动注册到被观察者上,才能接受通知。

  • 通知机制是推送模式,被观察者直接将消息推送给观察者。

应用场景:

  • 事件监听机制:浏览器的事件机制就是观察者模式的典型应用

  • 状态管理:Vue和React的状态管理库(Vuex和Redux)常用观察者模式来实现数据的响应式更新

手写观察者模式

"Observerd"类实现观察者模式。要求如下: "Observer"为观察者,"Observerd"为被观察者

  • 被观察者构造函数声明三个属性分别为"name"用于保存被观察者姓名、"state"用于保存被观察者状态、"observers"用于保存观察者们
  • 被观察者创建"setObserver"函数,用于保存观察者们,该函数通过数组的push函数将观察者参数传入"observers"数组中
  • 被观察者创建"setState"函数,设置该观察者"state"并且通知所有观察者,该函数首先通过参数修改被观察者的"state"属性,然后通过遍历"observers"数组分别调用各个观察者的"update"函数并且将该被观察者作为参数传入
  • 观察者创建"update"函数,用于被观察者进行消息通知,该函数需要打印(console.log)数据,数据格式为:小明正在走路。其中"小明"为被观察者的"name"属性,"走路"为被观察者的"state"属性
js
//被观察者
class Observerd {
    constructor(name) {
        this.name = name
        this.state = '走路'
        this.observers = []
    }
    setObserver(observer) {
        this.observers.push(observer)
    }
    setState(state) {
        this.state = state
        this.observers.forEach(observer => observer.update(this))
    }
}
//观察者
class Observer {
    constructor() {
        
    }
    update(observerd) {
        console.log(observerd.name + '正在' + observerd.state)
    }
}

发布订阅模式(Publish/Subscribe Pattern)

发布订阅模式通过引入一个中间代理(事件通道或消息代理),发布者发布消息到这个中间代理,订阅者订阅他们感兴趣的消息

核心概念:发布者和订阅者并不直接交互,他们通过消息代理进行解耦,发布者发布消息时,订阅者会收到事件通知

通信方向:可以是双向通信,多个发布者和多个订阅者可以互相独立工作

特点:

  • 发布者与订阅者是松耦合的,彼此之间并没有直接依赖。

  • 发布者和订阅者不需要互相感知彼此的存在,它们通过中间的消息代理来进行信息交换。

  • 订阅者在中间代理处订阅某类事件,代理会通知所有订阅者相应的事件。

手写发布订阅模式

完成"EventEmitter"类实现发布订阅模式。

  1. 同一名称事件可能有多个不同的执行函数:构造函数中创建”events“对象变量存放所有的事件
  2. 通过"on"函数添加事件:订阅事件。当总事件中不存在此事件时创建新的事件数组,当存在时将”fn“函数添加在该事件对应数组中
  3. 通过"emit"函数触发事件:发布事件,遍历该事件下的函数数组并全部执行
js
class EventEmitter{
    constructor(){
        this.events={}
    }

    // 添加事件:订阅事件
    on(event,fn){
        if(!this.events[event]){
            this.events[event]=[fn]
        }else{
            this.events[event].push(fn)
        }
    }

    // 触发事件:发布事件
    emit(event){
        if(this.events[event]){
            this.events[event].forEach(callback=>callback)
        }
    }
}

参考

https://blog.csdn.net/qq_28838891/article/details/124638456?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22124638456%22%2C%22source%22%3A%22qq_28838891%22%7D#t94