最近在試讀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函式)進行一些定製化的操作,比如進行節流操作,過濾操作,許可權控制等等,個人感覺會比較靈活一點。
先寫這麼多~有不對的歡迎指正~