09.08 「講得明白的設計模式」HTML5開發之JS觀察者模式 抹茶妹妹版

好叻,今天就來說說大名鼎鼎觀察者模式。

啥是觀察者模式呢?這就得從吃瓜群眾說起,有些吃瓜群眾最近想看強東哥最新狀況,就關注了強東哥。有些吃瓜群眾想看抹茶妹妹的最新狀況,就關注了抹茶妹妹。如果強東哥出了新狀況,那關注了強東哥的群眾就能立即得到強東哥的信息。

OK,那麼我們叫吃瓜群眾為訂閱者。頭條就是發佈者,根據訂閱的內容,來進行發佈。

「講得明白的設計模式」HTML5開發之JS觀察者模式 抹茶妹妹版

因此代碼實現該模式,通常需要兩個步驟:

1、初始化發佈者、訂閱者。

2、訂閱者需要註冊到發佈者,發佈者發佈消息時,依次向訂閱者發佈消息。

訂閱者註冊

「講得明白的設計模式」HTML5開發之JS觀察者模式 抹茶妹妹版

發佈者發佈消息

「講得明白的設計模式」HTML5開發之JS觀察者模式 抹茶妹妹版

觀察者模式的理解

我覺得還是發佈-訂閱模式的叫法更容易我們理解,這就類似我們在微信平臺訂閱了公眾號,當它有新的文章發表後,就會推送給我們所有訂閱的人。

我們可以看到這種模式的優點:

  • 我們作為訂閱者不必每次都去查看這個公眾號有沒有新文章發佈。
  • 公眾號作為發佈者會在合適時間通知我們。
  • 我們與公眾號之間不再強耦合在一起。公眾號不關心誰訂閱了它。
  • 不管你是男是女還是寵物狗,它只需要定時向所有訂閱者發佈消息即可。

很簡單的道理,過年的時候,群發祝福短信一定要比挨個發短信方便的多。

自定義事件

其實觀察者模式我們都曾使用過,就是我們熟悉的事件。但是內置的事件很多時候不能滿足我們的要求,所以我們需要自定義事件。

現在我們想實現這樣的功能,定義一個事件對象,它有以下功能:

  • 監聽事件(訂閱公眾號)
  • 觸發事件(公眾號發佈)
  • 移除事件(取訂公眾號)

當然我們不可能只訂閱一個公眾號,可能會有很多。所以我們要針對不同的事件設置不同的”鍵” 。

所以儲存事件的結構應該是這樣得:

//偽代碼
Event = {
name1: [回調函數1,回調函數2,...],
name2: [回調函數1,回調函數2,...],
name3: [回調函數1,回調函數2,...],
}

好,那麼就可以根據Event[事件名稱]獲取這個事件的所有回調函數,通過循環將所有回調函數進行執行。如果上面的原理都理解了,那麼我們就很容易理解下面簡易的訂閱者模式的源碼了。

代碼如下

var Event = (function(){
var list = {},
listen,
trigger,
remove;
listen = function(key,fn){ //監聽事件函數
if(!list[key]){
list[key] = []; //如果事件列表中還沒有key值命名空間,創建
}
list[key].push(fn); //將回調函數推入對象的“鍵”對應的“值”回調數組

};
trigger = function(){ //觸發事件函數
var key = Array.prototype.shift.call(arguments); //第一個參數指定“鍵”
msg = list[key];
if(!msg || msg.length === 0){
return false; //如果回調數組不存在或為空則返回false
}
for(var i = 0; i < msg.length; i++){
msg[i].apply(this, arguments); //循環回調數組執行回調函數
}
};
remove = function(key, fn){ //移除事件函數
var msg = list[key];
if(!msg){
return false; //事件不存在直接返回false
}
if(!fn){
delete list[key]; //如果沒有後續參數,則刪除整個回調數組
}else{
for(var i = 0; i < msg.length; i++){
if(fn === msg[i]){
msg.splice(i, 1); //刪除特定回調數組中的回調函數
}
}
}
};
return {
listen: listen,
trigger: trigger,
remove: remove
}
})();
var fn = function(data){
console.log(data + '的推送消息:xxxxxx......');
}
Event.listen('某公眾號', fn);
Event.trigger('某公眾號', '2016.11.26');
Event.remove('某公眾號', fn);


分享到:


相關文章: