对于观察者模式和发布者-订阅者模式的一些理解

最近在试读vue的源码(vue3都要出来了,vue2的源码还没去读,惭愧惭愧),发现自己对观察者以及发布者-订阅者模式的理解不够,立文来梳理记录一下自己的思路。

一、观察者模式和发布者-订阅者模式模式的区别

有些人认为观察者模式 === 发布者-订阅者模式,也有人觉得两者存在一些区别,其实两者的确有一些区别,但是两者的目的都是为了改善传统的通知机制,解耦通知方和被通知方的关系。那为什么发布者-订阅者模式存在区别呢?其实是因为后者相对于前者而言,多了一个类似于调度中心的存在,后者能集中管理多个主题对象,并且观察者和发布者之间是不存在直接关系的,在调度中心可以很方便的实现分发管理,这个特性让发布者-订阅者模式变得更加灵活。

二、观察者和发布者-订阅者模式的简单实现

观察者模式

class Observer {
    constructor(label) {
        this.label = label
    }
    update() {
        console.log(`update${this.label}`)
    }
}

class Target {
    constructor() {
        this.observerList = []
    }

    add(observer) {
        this.observerList.push(observer)
    }

    remove(observer) {
        this.observerList = this.observerList.filter(ob => ob !== observer)
    }

    notify() {
        this.observerList.forEach(ob => {
            ob.update()
        })
    }
}

let tar = new Target()

for (let i = 0; i < 10; i++) {
    tar.add(new Observer(i))
}

tar.notify()//打印update1到update10

复制代码

发布者-订阅者模式

class Publisher {
    constructor() {
        this.subscribers = {}
        this.cache = {}
    }

    add(type, fn) {
        if (Object.prototype.toString.call(fn) !== '[object Function]') return
        this.subscribers[type] ? this.subscribers[type].push(fn) : this.subscribers[type] = [fn]
        return this
    }

    publish(type, theme) {
        //存储主题信息
        this.cache[type] ? this.cache[type].push(theme) : this.cache[type] = [theme]
        let subscribers = this.subscribers[type]
        if (!subscribers || !subscribers.length) {
            console.warn('no subscriber in subscribers.')
            return this
        }
        subscribers.forEach(fn => fn.call(this, theme))
        return this
    }

    unbind(type, fn) {
        this.subscribers[type] = this.subscribers[type].filter(item => item !== fn)
        return this
    }

    history(type, fn) {
        let cache = this.cache[type] || []
        cache.forEach(item => fn.call(this, item))
        return this
    }
}

let sub1 = data => {
    console.log(`sub1${data}`)
}

let sub2 = data => {
    console.log(`sub2${data}`)
}

let sub3 = data => {
    console.log(`sub3${data}`)
}

let publisher = new Publisher()

publisher.add('click', sub1).add('click', sub2).add('change', sub3)

publisher.publish('click', '第一次click').publish('change', '第一次change')

publisher.unbind('click', sub1).publish('click', '第二次点击').history('click', data => {
    console.log('history' + data)
})

打印结果:
/***  
sub1第一次click
sub2第一次click
sub3第一次change
sub2第二次点击
history第一次click
history第二次点击
***/
复制代码

如以上代码,发布者订阅者模式可以在调度中心(相当于代码中的publish函数)进行一些定制化的操作,比如进行节流操作,过滤操作,权限控制等等,个人感觉会比较灵活一点。

先写这么多~有不对的欢迎指正~

猜你喜欢

转载自juejin.im/post/5c948cebe51d4508126c209f