观察者&&发布订阅

396 阅读2分钟

观察者和发布订阅区别

二者所需的角色数量有着明显的区别。观察者模式本身只需要2个角色便可成型,即观察者被观察者,其中被观察者是重点。而发布订阅需要至少3个角色来组成,包括发布者订阅者发布订阅中心,其中发布订阅中心是重点。

观察者模式发布订阅
2个角色3个角色
重点是被观察者重点是发布订阅中心

观察者模式

观察者模式一般至少有一个可被观察的对象 Subject ,可以有多个观察者去观察这个对象。二者的关系是通过被观察者主动建立的,被观察者至少要有三个方法——添加观察者、移除观察者、通知观察者

当被观察者将某个观察者添加到自己的观察者列表后,观察者与被观察者的关联就建立起来了。此后只要被观察者在某种时机触发通知观察者方法时,观察者即可接收到来自被观察者的消息

1. 被观察者实现

class Subject {
    constructor(){
        this.observerList = []
    }
    
    addObserver(observer){
        this.observerList.push(observer)
    }
    
    removeObserver(observer){
        const targetObserverIndex = this.observerList.findIndex(item => item.name === observer.name)
        this.observerList.splice(targetObserverIndex, 1)
    }
    
    notifyObserver(msg = ''){
        this.observerList.forEach(observer => observer.notified(msg))
    }
}

2. 观察者实现

class Observer {
    constructor(name){
        // name主要用于在被观察者中删除观察者时,区分不同的观察者
        this.name = name
    }
    notified(msg){
        // do something
        console.log(msg)
    }
}

3. 使用

const observer1 = new Observer("observer1")
const observer2 = new Observer("observer2")
const subject = new Subject()

subject.addObserver(observer1)
subject.addObserver(observer2)

subject.notifyObserver()

发布订阅

观察者模式相比,发布订阅核心基于一个中心来建立整个体系。其中发布者订阅者不直接进行通信,而是发布者将要发布的消息交由中心管理,订阅者也是根据自己的情况,按需订阅中心中的消息。所以发布订阅需要3种角色——发布订阅管理中心、发布者、订阅者

1. 发布订阅管理中心实现

class PubCenter{
    constrcutor(){
        this.events = {}
    }
    subscribe(type, cb){
        if(!this.events[type]){
            this.events[type] = []
        }
        this.events[type].push(cb)
    }
    publish(type){
        if(!this.events[type]){
            this.events[type] = []
        }
    }
    
    notified(type){
        this.events[type]?.forEach(cb => cb())
    }
}

2. 发布者实现

class Publisher{
    constructor(pubCenter){
        this.pubCenter = pubCenter
    }
    publish(type){
        this.pubCenter.publish(type)
    }
}

3. 订阅者中心

class Subscribe {
    constructor(pubCenter){
        this.pubCenter = pubCenter
    }
    subscribe(type, cb){
        this.pubCenter.subscribe(type, cb)
    }
}

参考

juejin.cn/post/697872…