2

观察者模式

实现原理

目标对象(或叫被观察者)给观察者发送消息,观察者立即将消息发送给所有订阅了获取该目标对象消息的订阅者。发布者与订阅者之间互相感知。

应用场景

  • Vue 中的 emit/on bus 模式, 跨组件通信。
  • Websocket 消息事件绑定。
class FEEvents {
    eventsMap = {}

    on(eventName, eventfn) {
        var _ref;
        let stack = (_ref = this.eventsMap[eventName]) != null ? _ref : this.eventsMap[eventName] = [];
        stack.push(eventfn);
        return this.eventsMap[eventName] = stack;
    }

    emit(eventName, data) {
        var _ref;
        var stack = (_ref = this.eventsMap[eventName]) != null ? _ref : this.eventsMap[eventName] = [];
        for (var _i = 0, _len = stack.length; _i < _len; _i++) {
            var fn = stack[_i];
            if (!fn) return false
            fn(data)
        }
    }

    off(eventName) {
        return (this.eventsMap[eventName]) != null ? this.eventsMap[eventName].length = 0 : void 0;
    }

    one(eventName, eventfn) {

        this.off(eventName)
        this.on(eventName, eventfn)
    }
}

let eventObj = new FEEvents()
eventObj.on('call', function (data) {
    console.log('my name is:', data)
})

eventObj.on('call', function (data) {
    console.log('my age is:', data)
})

eventObj.emit('call', 'no data')

eventObj.one('oneEvent', function () {
    console.log('one event 1....')
})

eventObj.one('oneEvent', function () {
    console.log('one event 2....')
})

eventObj.emit('oneEvent')

订阅发布模式

实现原理

观察者模式的变种。
与观察者不同的是,发布者与订阅者之间是互不感知的,发布者与订阅者之间含有一个用来处理消息获取和消息分发的中间者。

应用场景

vue中的数据改变视图更新的机制。

import Dep from './Dep'
//初始化被观察者
Class Watcher {
   constructor(data, name, updateFun) {
       this.data = data
       this.name = name
       this.updateFun = updateFun
       Dep.target = this
   }
   
    update() {
       this.updateFun()
    } 
}

//相当于观察者
Class Dep {
  constructor() {
     this.watchers = []
  }
  
  update() {
    for(let i=0; i<this.watcher.length; i++) {
       this.watcher[i].update()
    }
  }
  
  addWatcher(watcher) {
    this.watcher.push(watcher)
  }
}

function observe(data) {
   let keys = Object.keys(data)
   for(let i=0; i<keys.length; i++) {
      this.defineReactive(data, keys[i],    data[keys[i]])
   }
}

//设置响应式
function defineReactive (data, key, value) {

   observe(val)
   let dep = new Dep()
   Object.defineproperty(data, key, {
      set(val) {
         value = val
         dep.update()    
      },
      get() {
        if(Dep.target) {
          dep.addWatch(Dep.target)
        }
      }
   })
}

// 解析模版 例如读取到 {{age}}
// data: {age: 20, name: 'yy'}

//更新相关dom的方法
function update(value) {
   console.log('更新DOM的值:',value)
}
//取出age名称,设置成被观察者对象
new Watcher(data, 'age', update)
this.observe(data)
this.data[age]//触发get,添加订阅,将被观察者对象添加到观察者的列表中

被观察者在模版解析时创建,通过denfineProperty做为中间件来获取到被观察者消息的收集和处理被观察者消息的分发。

两者的区别

两者本质是一样的,先注册然后触发通知消息。
区别是,发布订阅模式的发布者与订阅者互不感知,之间有一个中间者来处理消息的订阅和消息的通知。

发布订阅者模式相对于观察者模式的用处,就是可以在消息发送和消息获取之间做一些额外的处理。例如Vue的数据改变视图的更新,就采用了发布订阅者模式,来实现只对dom上有依赖的变量更新做对应的视图更新处理。

用一个比喻来比方观察者模式和发布订阅者模式之间的区别:
观察者模式中的发布者和订阅者是购买个体奶牛的人和个体奶牛卖家之间的关系,没有中间商;而发布订阅模式中的发布者和订阅者是报社、邮局、报纸购买者中的报社和报纸购订阅者之间的关系,报纸订阅者向邮局订阅报纸,并从邮局拿报纸,而不是从报社直接订阅并拿到报纸,有中间者。

参考资料:

观察者模式

观察者模式与发布订阅者模式


贝er
58 声望6 粉丝

不仅仅是程序员