觀察者模式(Observer Pattern)
觀察者模式定義了對象間的一種一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都將得到通知,并自動(dòng)更新。觀察者模式屬于行為型模式,行為型模式關(guān)注的是對象之間的通訊,觀察者模式就是觀察者和被觀察者之間的通訊。
觀察者模式有一個(gè)別名叫“發(fā)布-訂閱模式”,或者說是“訂閱-發(fā)布模式”,訂閱者和訂閱目標(biāo)是聯(lián)系在一起的,當(dāng)訂閱目標(biāo)發(fā)生改變時(shí),逐個(gè)通知訂閱者。我們可以用報(bào)紙期刊的訂閱來形象的說明,當(dāng)你訂閱了一份報(bào)紙,每天都會(huì)有一份最新的報(bào)紙送到你手上,有多少人訂閱報(bào)紙,報(bào)社就會(huì)發(fā)多少份報(bào)紙,報(bào)社和訂報(bào)紙的客戶就是上面文章開頭所說的“一對多”的依賴關(guān)系。
發(fā)布訂閱模式(Pub-Sub Pattern)
其實(shí)24種基本的設(shè)計(jì)模式中并沒有發(fā)布訂閱模式,上面也說了,他只是觀察者模式的一個(gè)別稱。
但是經(jīng)過時(shí)間的沉淀,似乎他已經(jīng)強(qiáng)大了起來,已經(jīng)獨(dú)立于觀察者模式,成為另外一種不同的設(shè)計(jì)模式。
在現(xiàn)在的發(fā)布訂閱模式中,稱為發(fā)布者的消息發(fā)送者不會(huì)將消息直接發(fā)送給訂閱者,這意味著發(fā)布者和訂閱者不知道彼此的存在。在發(fā)布者和訂閱者之間存在第三個(gè)組件,稱為消息代理或調(diào)度中心或中間件,它維持著發(fā)布者和訂閱者之間的聯(lián)系,過濾所有發(fā)布者傳入的消息并相應(yīng)地分發(fā)它們給訂閱者。
舉一個(gè)例子,你在微博上關(guān)注了A,同時(shí)其他很多人也關(guān)注了A,那么當(dāng)A發(fā)布動(dòng)態(tài)的時(shí)候,微博就會(huì)為你們推送這條動(dòng)態(tài)。A就是發(fā)布者,你是訂閱者,微博就是調(diào)度中心,你和A是沒有直接的消息往來的,全是通過微博來協(xié)調(diào)的(你的關(guān)注,A的發(fā)布動(dòng)態(tài))。
觀察者模式和發(fā)布訂閱模式有什么區(qū)別?
我們先來看下這兩個(gè)模式的實(shí)現(xiàn)結(jié)構(gòu):

觀察者模式: 觀察者(Observer)直接訂閱(Subscribe)主題(Subject),而當(dāng)主題被激活的時(shí)候,會(huì)觸發(fā)(Fire Event)觀察者里的事件。
class Family {
constructor(name, role) {
this.name = name
this.role = role
// 存儲(chǔ)觀察者
this.subs = []
}
publish(doing) {
this.subs.forEach(sub => sub.cb(`${sub.subscribe.role}(${sub.subscribe.name}) 孩子(${this.name})在${doing}`))
}
subscribe(target, cb) {
target.subs.push({
subscribe: this,
cb
})
}
}
const mom = new Family('雪殷', 'mon')
const father = new Family('重樓', 'father')
const child = new Family('地瓜', 'child')
mom.subscribe(child, (doing) => console.log(doing))
father.subscribe(child, (doing) => console.log(doing))
child.publish('做運(yùn)動(dòng)')
child.publish('玩王者榮耀')
發(fā)布訂閱模式: 訂閱者(Subscriber)把自己想訂閱的事件注冊(Subscribe)到調(diào)度中心(Topic),當(dāng)發(fā)布者(Publisher)發(fā)布該事件(Publish topic)到調(diào)度中心,也就是該事件觸發(fā)時(shí),由調(diào)度中心統(tǒng)一調(diào)度(Fire Event)訂閱者注冊到調(diào)度中心的處理代碼。
// 事件中心
const Event = {
// 事件隊(duì)列
events: Object.create(null),
// 訂閱者
on: (type, cb) => {
let events = Event.events[type]
if (events === undefined) {
Event.events[type] = events = []
}
events.push(cb)
},
// 發(fā)布者
emit: (type) => {
let events = Event.events[type]
if (events === undefined) return
events.forEach(cb => cb())
},
off: (type, cb) => {
if (type === 'all') return Event.events = Object.create(null)
let events = Event.events[type]
if (events === undefined) return
for (let i = events.length - 1; i >= 0; i--) {
if (events[i] === cb) {
events.splice(i, 1)
}
}
}
}
// on
Event.on('click', () => {
console.log('click 1')
})
Event.on('change', () => {
console.log('change 1')
})
const input = () => console.log('input 1')
Event.on('input', input)
// emit
Event.emit('click')
Event.emit('change')
// off
Event.off('click', () => {
console.log('click 1')
})
Event.off('input', input)
Event.off('all')
console.log(Event)
【筆記不易,如對您有幫助,請點(diǎn)贊,謝謝】