觀察者模式
定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都將得到通知
什麼是觀察者模式?
釋出—訂閱模式又叫觀察者模式,它定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都將得到通知。在 JavaScript 開發中,我們一般用事件模型來替代傳統的釋出—訂閱模式。
舉個例子:
賣水果的張老闆和王老闆都要進一批香蕉,他們的水果都是在一個叫錢多多(下面統稱為錢老闆)的水果批發商那裡進的。當張老闆和王老闆到錢老闆那裡進水果的時候,錢老闆告訴張老闆和王老闆,香蕉還沒有到貨,得過幾天才到貨。無奈之下,張老闆和王老闆都把他們的電話號碼留在了錢老闆那裡,囑咐錢老闆,香蕉到貨後,第一時間通知他們。
上面錢老闆就扮演了釋出者的角色,張老闆和王老闆則扮演的是訂閱者角色。在香蕉到貨後,錢老闆會主動給張老闆和王老發訊息,讓兩位老闆來取香蕉。這樣的好處就是:香蕉沒到的這段時間,張老闆和王老闆可以做其他的事情,不用主動聯絡錢老闆,只需等待錢老闆的訊息即可。也就是程式程式碼中的時間上解耦,物件間解耦。
自定義事件
其實觀察者模式我們都曾使用過,就是我們熟悉的事件
但是內建的事件很多時候不能滿足我們的要求
所以我們需要自定義事件
現在我們想實現這樣的功能 定義一個事件物件,它有以下功能
- 監聽事件(訂閱事件)
- 觸發事件(事件釋出)
- 移除事件(取消訂閱事件)
當然我們不可能只訂閱一個事件,可能會有很多
所以我們要針對不同的事件設定不同的”鍵”
這樣我們儲存事件的結構應該是這樣的
EventList = {
evtName1: [回撥函式1,回撥函式2,...],
evtName2: [回撥函式1,回撥函式2,...],
evtName3: [回撥函式1,回撥函式2,...],
}
複製程式碼
程式碼如下
var createEventSys = function(){
return {
// 通過on介面監聽事件eventName
// 如果事件eventName被觸發,則執行callback回撥函式
on: function (eventName, callback) {
//如果Event物件沒有handles屬性,則給Event物件定義屬性handles,初始值為{}
//handles屬性是用來儲存事件和回撥執行函式的(即儲存訂閱的事件和觸發事件後執行的相應函式方法)
if(!this.handles){
this.handles={};
}
//如果handles中不存在事件eventName,則將事件儲存在handles中,同時初始化該事件對應的回撥邏輯函式集合
if(!this.handles[eventName]){
this.handles[eventName]=[];
}
//往handles中的eventName對應的回撥邏輯函式集合push回撥函式callback
this.handles[eventName].push(callback);
},
// 觸發事件 eventName
emit: function (eventName) {
//如果事件eventName有訂閱者,則依次執行事件eventName的訂閱者相應的回撥方法
if(this.handles[arguments[0]]){
for(var i=0;i<this.handles[arguments[0]].length;i++){
this.handles[arguments[0]][i](arguments[1]);
}
}
},
//移除事件 eventName
remove: function (eventName, fn) {
//判斷事件eventName是否存在fn這個觀察者,如果有,則移除事件eventName的fn觀察者
if(this.handles[eventName]){
for(var i=0; i<this.handles[eventName].length; i++){
if(this.handles[eventName][i] === fn){
this.handles[eventName].splice(i,1);
break;
}
}
}
}
};
}
var Event = createEventSys();
Event.on('test', function (result) {
console.log(result);
});
Event.on('test', function () {
console.log('test');
});
Event.emit('test', 'hello world'); // 輸出 'hello world' 和 'test'
//物件person1和物件person2擴充複用自定義系統
var person1 = {};
var person2 = {};
Object.assign(person1, createEventSys());
Object.assign(person2, createEventSys());
person1.on('call1', function () {
console.log('person1');
});
person2.on('call2', function () {
console.log('person2');
});
person1.emit('call1'); // 輸出 'person1'
person1.emit('call2'); // 沒有輸出
person2.emit('call1'); // 沒有輸出
person2.emit('call2'); // 輸出 'person2'
複製程式碼
如上面程式碼這樣,我們用觀察者模式就實現了一個基本完善的自定義事件系統。
總結
觀察者模式有兩個明顯的優點
時間上解耦
物件間解耦
在前端開發中,很多地方都適合用觀察者模式來做,在適當的地方善用觀察者模式
希望這篇文章對大家有幫助,喜歡的話,請關注我,我會持續更新一些技術文章到我的掘金主頁,謝謝大家支援!