“发布-订阅模式”和“观察者模式”有区别吗?

536 阅读3分钟

今天面试的时候,被问到设计模式,答了几个之后(没有讲观察者),面试官又让我讲一下观察者模式,我直接回答了“发布-订阅模式和观察者模式”不就是一个东西吗?过后重新翻阅了一下资料,细思惶恐。于是开始写作本文来加深自己对这两个模式的理解。希望能对其他小伙伴有用处,如果有错误,请一定要拍醒我~

观察者模式

观察者模式在软件设计中是一个对象,维护一个依赖列表,当任何状态发生改变自动通知它们。 --维基百科

观察者模式中主要对象:Observe、Subject。

当subject发生改变的时候通知全部的观察者。subject需要维护一系列观察者,方便添加和删除观察者。

基本代码框架:

// 这里添加一个ObserverList 主要是为了后续补充方法,比如通知具有过滤性质的时候
class ObserverList {
    constructor() {
        this.observerList = []
    }
    add(obs) {
        this.observerList.push(obs)
    }
    empty() {
        this.observerList = []
    }
    getCount() {
        return this.observerList.length;
    }
    get(index) {
        if (index > -1 && index < this.observerList.length) {
            return this.observerList[index]
        }
    }
    remove(observer) {
        let index = this.observerList.indexOf(observer) 
        if (index > -1) {
            this.observerList.splice(index)
        }
    }
}
class Object {
    update() {
        console.log('update')
    }
}
class Subject {
    constructor() {
        this.observerList = new ObserverList()
    }
    addObs(obs) {
        this.observerList.add(obs)
    }
    // 通知
    notify() {
        let count = this.observerList.getCount()
        for (let i = 0; i < count; ++i) {
            this.observerList.get(i).update()
        }
    }
}
let sub = new Subject()
let obj1 = new Object()
let obj2 = new Object()

sub.addObs(obj1)       
sub.addObs(obj2)        
sub.notify()

发布-订阅模式

发布-订阅模式定义了一种一对多的依赖关系。当一个对象的状态发生改变的时候,所有依赖它的对象就将得到通知。事件模型实际上就是一种发布-订阅模式。

这样看来,好像和观察者的概念差不多? 再来看一波维基百科

在发布-订阅模式,消息的发送方,叫做发布者(publishers),消息不会直接发送给特定的接收者(订阅者)。

意思就是发布者和订阅者不知道对方的存在。需要一个第三方,它将订阅者和发布者串联起来,它过滤和分配所有输入的消息。可以说是一个调度中心。换句话说,发布-订阅模式用来处理不同系统组件的信息交流,即使这些组件不知道对方的存在。

class Pub {
    constructor() {
        this.subscribers = {}
    }
    // 订阅
    subscribe(event, callback) {
        if (!this.subscribers[event]) {
            this.subscribers[event] = []
        }
        this.subscribers[event].push(callback)
    }
    // 取消订阅
    cancelSubscribe(event, callback) {
        if (this.subscribers[event]) {
            this.subscribers[event] = this.subscribers[event].filter(fn => callback !== fn)
        }
    }
    // 发布
    publish(event, ...data) {
        if (this.subscribers[event]) {
            this.subscribers[event].forEach(function(callback) {
                callback(...data)
            })
        }
    }
  }
  

let pub = new Pub()
pub.subscribe('sub1',(...data) => {
    console.log(data)
})
pub.subscribe('sub2',(...data) => {
    console.log(data)
})
pub.publish('sub1','hello ','JavaScript')
pub.publish('sub2','hello ','Node')

两者的区别

个人觉得并没有多大区别,观察者模式中观察者和订阅者相对比较耦合,而发布-订阅模式通过提供一个调度中心,使得发布者和订阅者并不需要知道对方是谁就可以达到发布订阅的目的。

观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的。

vue中用的也是发布-订阅模式。通过一个Dep类作为调度中心。

参考链接

www.sohu.com/a/207062452…

www.jianshu.com/p/594f018b6…

blog.csdn.net/ljw_josie/a…

《JavaScript设计模式与开发实践》

《JavaScript设计模式》