之前一直都认为观察者模式和发布订阅模式是一回事,包括网上的很多文章也是这么写的,但有一次面试中被问到两者的区别,直接懵了答不出来,经过最近的一些学习,慢慢理解了两者的不同。
在我看来,两者最主要的区别在于是否有中间的调度中心。
- 观察者模式把订阅者维护在发布者这里,需要发布消息时直接发消息给订阅者。在观察者模式中,发布者本身是知道订阅者存在的。
- 而发布/订阅模式中,发布者并不维护订阅者,也不知道订阅者的存在,所以也不会直接通知订阅者,而是通知调度中心,由调度中心通知订阅者。
由以上的描述可以看出,发布订阅模式是松散耦合的,而观察者模式强耦合。
观察者模式的场景:Vue的依赖追踪,原生事件。
发布订阅模式的场景: React的合成事件,vue组件间通信的EventBus。
观察者模式的一个例子:
class Observer {
constructor (fn) {
this.update = fn
}
}
class Subject {
constructor () {
this.observers = []
}
addObserver (observer) {
this.observers.push(observer)
}
removeObserver (observer) {
const delIndex = this.observers.indexOf(observer)
this.observers.splice(delIndex, 1)
}
notify () {
this.observers.forEach(observer => {
observer.update()
})
}
}
var subject = new Subject()
var ob1 = new Observer(function () {
console.log('ob1 callback run')
})
subject.addObserver(ob1)
var ob2 = new Observer(function () {
console.log('ob2 callback run')
})
subject.addObserver(ob2)
subject.notify()
发布/订阅模式:
class EventBus {
constructor () {
this.events = Object.create(null)
}
on (event, fn) {
this.events.event = this.events.event || []
this.events.event.push(fn)
}
off (event, fn) {
const index = (this.events.event || []).indexOf(fn)
if (index < -1) {
return
} else {
this.events.event.splice(index, 1)
}
}
fire (event) {
this.events.event.forEach(fn => fn())
}
}
var bus = new EventBus()
bus.on('onclick', function () {
console.log('click1 fire')
})
bus.on('onclick', fn=function () {
console.log('click2 fire')
})
bus.fire('onclick')