观察者模式实现
鉴于最近在归纳总结一些常用的设计模式,刚好最近小程序项目中跨组件的异步通信中仿造vue总线机制实现了一个用于订阅和发布消息的对象。所以将js中观察者模式实现总结如下。
简介
- 目的:实现发布订阅的功能,取消订阅功能的observer对象
- 是一种解决封装良好的组件之间异步通信的一种方式
- 典型应用是vue中的总线机制
主要包含的内容
- 发布函数,发布的时候可能会携带参数
- 订阅函数,收到消息之后执行回调函数
- 一个缓存订阅者以及订阅者的回调函数的列表
- 取消订阅函数。(需要考虑情况较多)
代码实现如下
function Observer() {
this.cache = {} //用于存储订阅的事件名称以及回调函数列表的键值对
}
Observer.prototype.on = function (key,fn) {//key:订阅消息的类型的标识(名称),fn收到消息之后执行的回调函数
if(!this.cache[key]){
this.cache[key]=[]
}
this.cache[key].push(fn)
}
Observer.prototype.emit = function (key) { //arguments 是发布消息时候携带的参数数组
if(this.cache[key]&&this.cache[key].length>0){
var fns = this.cache[key]
}
for(let i=0;i<fns.length;i++){
Array.prototype.shift.call(arguments)
fns[i].apply(this,arguments)
}
}
// remove 的时候比较有意思,如果你直接传入一个匿名函数fn,那么你在remove的时候是无法找到这个函数并且把它移除的,变通方式是传入一个
//指向该函数的指针,而 订阅的时候存入的也是这个指针
Observer.prototype.remove = function (key,fn) {
let fns = this.cache[key]
if(!fns||fns.length===0){
return
}
//如果没有传入fn,那么就是取消所有该事件的订阅
if(!fn){
fns=[]
}else {
fns.forEach((item,index)=>{
if(item===fn){
fns.splice(index,1)
}
})
}
}
//example
var obj = new Observer()
obj.on('hello',function (a,b) {
console.log(a,b)
})
obj.emit('hello',1,2)
//取消订阅事件的回调必须是具名函数
obj.on('test',fn1 =function () {
console.log('fn1')
})
obj.on('test',fn2 = function () {
console.log('fn2')
})
obj.remove('test',fn1)
obj.emit('test')
实际开发中的使用方式
- vue中在vue对象上就实现了该发布订阅功能。传送门
- 仿造vue中的总线机制在wepy的小程序项目中定制一个用于组件之间异步通信的总线。
//app.wpy中挂载在wepy对象上:
wepy.$bus = new Observer();
//不同组件(或者页面)之中的分别调用
wepy.$bus.on('test2',function(){
console.log('this is test 2')
})
wepy.$bus.emit('test2')