發(fā)布-訂閱模式

  • 定義
    發(fā)布—訂閱模式又叫觀察者模式雁比,它定義對象間的一對多的依賴關(guān)系稚虎,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都將得到通知偎捎。
  • 步驟
    下面是實現(xiàn)發(fā)布—訂閱模式的步驟:

1蠢终、先要指定好誰充當發(fā)布者(比如售樓處)

2、然后給發(fā)布者添加一個緩存列表茴她,用于存放回調(diào)函數(shù)以便通知訂閱者(售樓處的花名冊)

3寻拂、最后發(fā)布消息的時候,發(fā)布者會遍歷這個緩存列表败京,依次觸發(fā)里面存放的訂閱者回調(diào)函數(shù)(遍歷花名冊兜喻,挨個發(fā)短信)

另外,還可以往回調(diào)函數(shù)里填入一些參數(shù)赡麦,訂閱者可以接收這些參數(shù)朴皆。這是很有必要的帕识,比如售樓處可以在發(fā)給訂閱者的短信里加上房子的單價、面積遂铡、容積率等信息肮疗,訂閱者接收到這些信息之后可以進行各自的處理

var salesOffices = {}; // 定義售樓處
salesOffices.clientList = []; // 緩存列表,存放訂閱者的回調(diào)函數(shù)
salesOffices.listen = function( fn ){ // 增加訂閱者
    this.clientList.push( fn ); // 訂閱的消息添加進緩存列表
};
salesOffices.trigger = function(){ // 發(fā)布消息
    for( var i = 0, fn; fn = this.clientList[ i++ ]; ){
        fn.apply( this, arguments ); // (2) // arguments 是發(fā)布消息時帶上的參數(shù)
    }
};
salesOffices.listen( function( price, squareMeter ){ // 小明訂閱消息
    console.log( '價格= ' + price );
    console.log( 'squareMeter= ' + squareMeter );
});

salesOffices.listen( function( price, squareMeter ){ // 小紅訂閱消息
    console.log( '價格= ' + price );
    console.log( 'squareMeter= ' + squareMeter );
});

salesOffices.trigger( 2000000, 88 ); // 輸出:200 萬扒接,88 平方米
salesOffices.trigger( 3000000, 110 ); // 輸出:300 萬伪货,110 平方米

但這里還存在一些問題〖卣看到訂閱者接收到了發(fā)布者發(fā)布的每個消息碱呼,雖然小明只想買88平方米的房子,但是發(fā)布者把110平方米的信息也推送給了小明宗侦,這對小明來說是不必要的困擾愚臀。所以有必要增加一個標示key,讓訂閱者只訂閱自己感興趣的消息矾利。改寫后的代碼如下:

var salesOffices = {}; // 定義售樓處
salesOffices.clientList = []; // 緩存列表姑裂,存放訂閱者的回調(diào)函數(shù)

salesOffices.listen = function( key, fn ){
    if ( !this.clientList[ key ] ){ // 如果還沒有訂閱過此類消息,給該類消息創(chuàng)建一個緩存列表
        this.clientList[ key ] = [];
    }
    this.clientList[ key ].push( fn ); // 訂閱的消息添加進消息緩存列表
};

salesOffices.trigger = function(){ // 發(fā)布消息
    var key = Array.prototype.shift.call( arguments ), // 取出消息類型
    fns = this.clientList[ key ]; // 取出該消息對應(yīng)的回調(diào)函數(shù)集合
    if ( !fns || fns.length === 0 ){ // 如果沒有訂閱該消息男旗,則返回
        return false;
    }
    for( var i = 0, fn; fn = fns[ i++ ]; ){
        fn.apply( this, arguments ); // (2) // arguments 是發(fā)布消息時附送的參數(shù)
    }
};

salesOffices.listen( 'squareMeter88', function( price ){ // 小明訂閱88 平方米房子的消息
    console.log( '價格= ' + price ); // 輸出: 2000000
});

salesOffices.listen( 'squareMeter110', function( price ){ // 小紅訂閱110 平方米房子的消息
    console.log( '價格= ' + price ); // 輸出: 3000000
});

salesOffices.trigger( 'squareMeter88', 2000000 ); // 發(fā)布88 平方米房子的價格
salesOffices.trigger( 'squareMeter110', 3000000 ); // 發(fā)布110 平方米房子的價格
  • 通用實現(xiàn)
var event = {
    clientList: [],
    listen: function( key, fn ){
        if ( !this.clientList[ key ] ){
            this.clientList[ key ] = [];
        }
            this.clientList[ key ].push( fn ); // 訂閱的消息添加進緩存列表
        },
        trigger: function(){
            var key = Array.prototype.shift.call( arguments ), // (1);
            fns = this.clientList[ key ];
            if ( !fns || fns.length === 0 ){ // 如果沒有綁定對應(yīng)的消息
                return false;
            }
            for( var i = 0, fn; fn = fns[ i++ ]; ){
                fn.apply( this, arguments ); // (2) // arguments 是trigger 時帶上的參數(shù)
            }
        }
    };

再定義一個installEvent函數(shù)舶斧,這個函數(shù)可以給所有的對象都動態(tài)安裝發(fā)布—訂閱功能:

var installEvent = function( obj ){
    for ( var i in event ){
        obj[ i ] = event[ i ];
    }
};

下面給售樓處對象salesOffices動態(tài)增加發(fā)布—訂閱功能

var salesOffices = {};
installEvent( salesOffices );
salesOffices.listen( 'squareMeter88', function( price ){ // 小明訂閱消息
    console.log( '價格= ' + price );
});
salesOffices.listen( 'squareMeter100', function( price ){ // 小紅訂閱消息
    console.log( '價格= ' + price );
});
salesOffices.trigger( 'squareMeter88', 2000000 ); // 輸出:2000000
salesOffices.trigger( 'squareMeter100', 3000000 ); // 輸出:3000000
  • 取消訂閱事件
    有時候,也許需要取消訂閱事件的功能察皇。比如小明突然不想買房子了茴厉,為了避免繼續(xù)接收到售樓處推送過來的短信,小明需要取消之前訂閱的事件∪猛現(xiàn)在給event對象增加remove方法
event.remove = function( key, fn ){
    var fns = this.clientList[ key ];
    if ( !fns ){ // 如果key 對應(yīng)的消息沒有被人訂閱呀忧,則直接返回
        return false;
    }
    if ( !fn ){ // 如果沒有傳入具體的回調(diào)函數(shù)师痕,表示需要取消key 對應(yīng)消息的所有訂閱
        fns && ( fns.length = 0 );
    }else{
        for ( var l = fns.length - 1; l >=0; l-- ){ // 反向遍歷訂閱的回調(diào)函數(shù)列表
            var _fn = fns[ l ];
            if ( _fn === fn ){
                fns.splice( l, 1 ); // 刪除訂閱者的回調(diào)函數(shù)
            }
        }
    }
};
var salesOffices = {};
var installEvent = function( obj ){
    for ( var i in event ){
        obj[ i ] = event[ i ];
    }
}
installEvent( salesOffices );

salesOffices.listen( 'squareMeter88', fn1 = function( price ){ // 小明訂閱消息
    console.log( '價格= ' + price );
});

salesOffices.listen( 'squareMeter88', fn2 = function( price ){ // 小紅訂閱消息
    console.log( '價格= ' + price );
});

salesOffices.remove( 'squareMeter88', fn1 ); // 刪除小明的訂閱
salesOffices.trigger( 'squareMeter88', 2000000 ); // 輸出:2000000
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末溃睹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子胰坟,更是在濱河造成了極大的恐慌因篇,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笔横,死亡現(xiàn)場離奇詭異竞滓,居然都是意外死亡,警方通過查閱死者的電腦和手機吹缔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門商佑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厢塘,你說我怎么就攤上這事茶没〖∮模” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵抓半,是天一觀的道長喂急。 經(jīng)常有香客問我,道長笛求,這世上最難降的妖魔是什么廊移? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮探入,結(jié)果婚禮上狡孔,老公的妹妹穿的比我還像新娘。我一直安慰自己蜂嗽,他們只是感情好步氏,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著徒爹,像睡著了一般荚醒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上隆嗅,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天界阁,我揣著相機與錄音,去河邊找鬼胖喳。 笑死泡躯,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的丽焊。 我是一名探鬼主播较剃,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼技健!你這毒婦竟也來了写穴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤雌贱,失蹤者是張志新(化名)和其女友劉穎啊送,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體欣孤,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡馋没,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了降传。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片篷朵。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖婆排,靈堂內(nèi)的尸體忽然破棺而出声旺,到底是詐尸還是另有隱情控硼,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布艾少,位于F島的核電站卡乾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏缚够。R本人自食惡果不足惜幔妨,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谍椅。 院中可真熱鬧误堡,春花似錦、人聲如沸雏吭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杖们。三九已至悉抵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摘完,已是汗流浹背姥饰。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留孝治,地道東北人列粪。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像谈飒,于是被迫代替她去往敵國和親岂座。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容