定义:
发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖他的对象都将得到通知。
实现发布-订阅
的步骤:
- 首先要指定好谁充当发布者
- 然后发布者添加一个缓存列表,用于存放回调函数以便通知订阅者
- 最后发布消息时,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数
另外,我们还可以往回调函数里填入一些参数,订阅者可以接收这些参数。
发布-订阅模式通用实现
let event = {
clientList:{}, //用于存放回调函数的缓存列表
listen:(key,fn)=>{
if(!this.clientList[key]){
this.clientList[key] = [];
}
this.clientList[key].push(fn); //订阅的消息添加进缓存列表
},
trigger:()=>{
let key = Array.prototype.shift.call(arguements);
let fns = this.clientList[key];
if(!fns || fns.length === 0){
return false;
}
for(let i=0; fn; fn=fns[i++]){
fn.apply(this, arguements); // arguements 是 trigger 时带上的参数
}
}
}
//再定义一个 installEvent 函数,这个函数可以给所有对象都动态安装发布-订阅功能
let installEvent = (obj)=>{
for(let i in event){
obj[i] = event[i]
}
}
//举一个例子,售楼部在房价定下来时会通知客户房屋价格
let saleOffices = {};
installEvent(saleOffices);
saleOffices.listen('maria',(price)=>{ //maria订阅消息
console.log('价格=' + price);
})
saleOffices.listen('peter',(price)=>{ //peter订阅消息
console.log('价格=' + price);
})
saleOffices.trigger('maria',7000)// 价格=7000
saleOffices.trigger('peter',10000)// 价格=10000
上面是给对象添加发布-订阅功能,当我们想要取消订阅时该怎么办呢?下面我们来对上面代码做个修改
let Event = (function(){
let clientList = {},
listen,
trigger,
remove;
listen = (key,fn)=>{
if(!this.clientList[key]){
this.clientList[key] = [];
}
this.clientList[key].push(fn); //订阅的消息添加进缓存列表
};
trigger = ()=>{
let key = Array.prototype.shift.call(arguements);
let fns = this.clientList[key];
if(!fns || fns.length === 0){
return false;
}
for(let i=0; fn; fn=fns[i++]){
fn.apply(this, arguements); // arguements 是 trigger 时带上的参数
}
};
remove = (key,fn)=>{
let fns = this.clientList[key];
if(!fns){ // 如果 key 对应的消息没有被人订阅,则直接返回
return false
}
if(!fn){ //如果没有传入具体的回调函数,表示需要取消 key 对应消息的所有订阅
fns && (fns.length = 0)
}else{
for(let i=0; i<fns.length; i++){
let _fn=fns[i];
if(_fn===fn){
fns.split(i,1); //删除订阅者的回调函数
}
}
}
};
return {
listen:listen,
trigger:trigger,
remove:remove
}
})()
//举一个例子,售楼部在房价定下来时会通知客户房屋价格
let fn1 = (price)=>{ //maria订阅消息
console.log('价格=' + price);
}
Event.listen('maria',fn1)//maria订阅消息
Event.trigger('maria',10000)// 价格=10000
Event.remove('maria',fn1)// 删除maria的订阅
Event.trigger('maria',10000)// 已被取消订阅,无打印信息
小结:
发布-订阅模式的优点非常明显,一为时间上的解耦,二为对象之间的解耦。从架构上看,无论时MVC还是MVVM都少不了发布-订阅模式的参与。