Vue响应式原理(一)观察者/发布订阅模式

1,451 阅读2分钟

观察者模式 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


参考