观察者模式 VS 发布订阅模式
“发布/订阅模式"(publish-subscribe pattern)
"观察者模式"(observer pattern)
观察者模式和发布订阅模式严格意义上并不相同,发布订阅模式是观察者模式的一种拓展实现
他们的区别在于发布订阅模式多了个通道,如图:
打个比方,你(发布者)是个很受欢迎的人,你有很多朋友(观察者),他们都很关注你的动向,提前告诉你“结婚了可千万记着我”(订阅)
于是你逐一把他们的联系方式记在通讯录上(缓存列表),然后在你要结婚的时候,要逐个发请帖(触发回调),并且可以在请贴上写明婚礼的时间地点(给回调传参)
朋友们收到请帖就可以根据时间地点准时出席(接受参数执行方法)
代码实现
先定义一个主题类
class Subject{
constructor(){
this.observers=[]
}
addObserver(observer){}
removeObserve(){}
notify(){}
}
再定义一个观察者类
class Observer{
update(){}
subscribeTo(subject){
subject.addObserver(this)
}
}
大体框架定下来后,填充一下各方法的内容
class Subject{
constructor(){
this.observers=[]
}
addObserver(observer){
this.observers.push(observer)
}
removeObserve(observer){
let index=this.observers.indexOf(observer)
if(index>-1){
this.observer.splice(index,1)
}
}
notify(){
this.observers.forEach(observer=>{
observer.update()
})
}
}
class Observer{
update(){}
subscribeTo(subject){
subject.addObserver(this)
}
}
//测试
let subject=new Subject()
let observer1=new Observer()
let observer2=new Observer()
let observer3=new Observer()
observer1.update=function(){
console.log('1 update')
}
observer2.update=function(){
console.log('2 update')
}
observer3.update=function(){
console.log('3 update')
}
observer1.subscribeTo(subject)
observer2.subscribeTo(subject)
observer3.subscribeTo(subject)
subject.notify()//依次输出1 update / 2 update / 3 update
观察者模式应用于EventBus
class EventBus{
constructor(){
this.map=[]
}
on(type,handler){
this.map[type]=(this.map[type] || []).concat(handler)
}
off(type,handler){
if(this.map[type]){
if(!handler){
delete this.map[type]
}else{
let index=this.map[type].indexOf(handler)
this.map[type].splice(index,1)
}
}
}
fire(type,data){
this.map[type] && this.map[type].forEach(handler=>handler(data))
}
}
const eventBus=new EventBus()
eventBus.on('click',data=>{
console.log(data)
}
eventBus.fire('click',{a:1,b:2})
在发布订阅模式中,发布者和订阅者之间多了一个发布通道;一方面从发布者接收事件,另一方面向订阅者发布事件;订阅者需要从事件通道订阅事件
//订阅者
class Subscriber{
update(){}
//update(event){}
subscribeTo(channel){
channel.addSubscriber(this)
}
}
//发布者
class Publisher{
notify(channel){
channel.publish()
//channel.publish(event)
}
}
//中间通道
class Channel{
constructor(){
this.subscribers=[]
}
addSubscriber(subscriber){
this.subscribers.push(subscriber)
}
removeSubscriber(subscriber){
let index=this.observers.indexOf(subscriber)
if(index>-1){
this.subscribers.splice(index,1)
}
}
publish(){
//publish(event){
this.subscribers.forEach(subscriber=>{
subscriber.update()
//subscriber.update(event)
})
}
}
//测试,new一个chanel对象、publisher对象和三个subscriber对象
let channel=new Channel()
let publisher=new Publisher()
let subscriber1=new Subscriber()
let subscriber2=new Subscriber()
let subscriber3=new Subscriber()
subscriber1.update=function(){
console.log('1 update')
}
subscriber2.update=function(){
console.log('2 update')
}
subscriber3.update=function(){
console.log('3 update')
}
//订阅者向中间通道订阅
subscriber1.subscribeTo(channel)
subscriber2.subscribeTo(channel)
subscriber3.subscribeTo(channel)
//发布者只向中间通道发布事件
publisher.notify(channel)
以上都是发布者向订阅者推送数据,也可以实现为订阅者主动拉取数据。
Vue响应式原理(二)Observer、Dep、Watcher
参考