定義:
發佈-訂閱模式又叫觀察者模式,它定義對象間的一種一對多的依賴關係,當一個對象的狀態發生變化時,所有依賴他的對象都將得到通知。
實現發佈-訂閱
的步驟:
- 首先要指定好誰充當發佈者
- 然後發佈者添加一個緩存列表,用於存放回調函數以便通知訂閱者
- 最後發佈消息時,發佈者會遍歷這個緩存列表,依次觸發裏面存放的訂閱者回調函數
另外,我們還可以往回調函數裏填入一些參數,訂閱者可以接收這些參數。
發佈-訂閱模式通用實現
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都少不了發佈-訂閱模式的參與。