第八節、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都少不了發佈-訂閱模式的參與。

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