第八节、JavaScript 设计模式——发布-订阅模式

定义:发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖他的对象都将得到通知。

实现发布-订阅的步骤:

  1. 首先要指定好谁充当发布者
  2. 然后发布者添加一个缓存列表,用于存放回调函数以便通知订阅者
  3. 最后发布消息时,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数

另外,我们还可以往回调函数里填入一些参数,订阅者可以接收这些参数。

发布-订阅模式通用实现
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都少不了发布-订阅模式的参与。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章