发布订阅和观察者
观察者模式(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"类实现发布订阅模式。
- 同一名称事件可能有多个不同的执行函数:构造函数中创建”events“对象变量存放所有的事件
- 通过"on"函数添加事件:订阅事件。当总事件中不存在此事件时创建新的事件数组,当存在时将”fn“函数添加在该事件对应数组中
- 通过"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)
}
}
}