国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript設(shè)計(jì)模式之發(fā)布-訂閱模式(觀察者模式)-Part1

muzhuyu / 2408人閱讀

摘要:設(shè)計(jì)模式與開發(fā)實(shí)踐讀書筆記。發(fā)布訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關(guān)系。附設(shè)計(jì)模式之發(fā)布訂閱模式觀察者模式數(shù)據(jù)結(jié)構(gòu)和算法系列棧隊(duì)列優(yōu)先隊(duì)列循環(huán)隊(duì)列設(shè)計(jì)模式系列設(shè)計(jì)模式之策略模式

《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》讀書筆記。

發(fā)布-訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關(guān)系。當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴它的對象都將得到通知。

例如:在segmentfault我們關(guān)注了某一個(gè)問題,這個(gè)時(shí)候可以說是訂閱了這個(gè)問題的消息。當(dāng)該問題有了新的回答、評論的時(shí)候,segmentfault系統(tǒng)就會(huì)遍歷關(guān)注了這個(gè)問題的用戶,一次給用戶發(fā)消息。

現(xiàn)在看看如何一步步實(shí)現(xiàn)發(fā)布-訂閱模式。

首先,指定好發(fā)布者(如 segmentfault 的 問題系統(tǒng))

接著,給發(fā)布者添加一個(gè)緩存列表,用于存放回調(diào)函數(shù)以便通知訂閱者(問題系統(tǒng)的記錄表)

最后,當(dāng)發(fā)布者發(fā)布消息的時(shí)候,會(huì)遍歷緩存列表,依次觸發(fā)里面的回調(diào)函數(shù)(遍歷記錄表,逐個(gè)發(fā)消息)

我們還可以在回調(diào)函數(shù)里面加入一些參數(shù),訂閱者可以接收這些參數(shù),進(jìn)行各自的處理。

var sgQuestionSystem = {};    // 定義segmentfault的問題系統(tǒng)

/* 
 * 緩存列表
 * clientList: {
 *    key: [
 *        id: ,        // 唯一標(biāo)識
 *        fn: null          // 存放回調(diào)函數(shù)
 *    ]
 * }
 * 
*/
sgQuestionSystem.clientList = {};

/* 
 * 添加訂閱者(訂閱函數(shù)),將訂閱的類型與回調(diào)函數(shù)加入緩存列表
 * key: 消息的類型
 * id: 訂閱的唯一標(biāo)識
 * fn: 訂閱的回調(diào)函數(shù)
*/
sgQuestionSystem.listen = function(key, id, fn) {
    if(!this.clientList[key]) {            // 若緩存列表沒有該類型的消息,給該類消息初始化
        this.clientList[key] = []
    }
   
    this.clientList[key].push({            // 將訂閱的id, 回調(diào)函數(shù)添加到對應(yīng)的消息列表里
        id: id,                         
        fn: fn                          
    })
}

// 發(fā)布消息(發(fā)布函數(shù)), 依次通知訂閱者
sgQuestionSystem.trigger = function () {
    var key = Array.prototype.shift.call(arguments),    // 取出消息類型
        fns = this.clientList[key];                     // 取出該消息對應(yīng)的回調(diào)函數(shù)集合
    
    if(!fns || fns.length == 0) {                      // 若訂閱列表沒有該類型的回到函數(shù),則返回
        return false;                                   
    }
    
    for(var i = 0; i< fns.length; i++) {
         fns[i].fn.apply(this, arguments);               // arguments是發(fā)布消息時(shí)附送的參數(shù),去掉了key
    }
}

現(xiàn)在,我們來進(jìn)行一些簡單的測試:

// 張三訂閱問題A
sgQuestionSystem.listen("questionA", 3, function(questionTitle, content) {
    console.log("張三您在早前訂閱了問題:questionA");
    console.log("現(xiàn)" + questionTitle + "有了新動(dòng)態(tài)");
    console.log("內(nèi)容為:" + content);
});

// 李四訂閱問題A
sgQuestionSystem.listen("questionB", 4, function(questionTitle, content) {
    console.log("李四您在早前訂閱了問題:questionB");
    console.log("現(xiàn)" + questionTitle + "有了新動(dòng)態(tài)");
    console.log("內(nèi)容為:" + content);
})

// 問題系統(tǒng)發(fā)布消息
sgQuestionSystem.trigger("questionA", "問題A", "王五回答了問題A");
sgQuestionSystem.trigger("questionB", "問題B", "吳六回答了問題B");

至此,我們實(shí)現(xiàn)了一個(gè)簡單的發(fā)布-訂閱模式,訂閱者可以訂閱自己感興趣的事件了。

各位看官,看累了嗎? 看累的話點(diǎn)一下收藏,以便您看續(xù)集。若您還是精力充沛,那就繼續(xù)擼吧。

上部分,我們實(shí)現(xiàn)了一個(gè)問題系統(tǒng)的發(fā)布-訂閱模式,現(xiàn)在,我們要實(shí)現(xiàn)一個(gè)文章的發(fā)布-訂閱模式,這時(shí)候,該怎么辦?將上面的代碼ctrl + c, ctrl + v, 再改下名字?還是有更好的解決方案?

答案顯然是有的,我們可以將發(fā)布-訂閱功能模塊提取出來,放在一個(gè)多帶帶的對象里面:

var publishSubscribeEvent = {

    
    /* 
     * 緩存列表
     * clientList: {
     *    key: [
     *        id: ,        // 唯一標(biāo)識
     *        fn: null          // 存放回調(diào)函數(shù)
     *    ]
     * }
     * 
    */
    clientList: {},
    
    /* 
     * 添加訂閱者(訂閱函數(shù)),將訂閱的類型與回調(diào)函數(shù)加入緩存列表
     * key: 消息的類型
     * id: 訂閱的唯一標(biāo)識
     * fn: 訂閱的回調(diào)函數(shù)
    */
    listen: function(key, id, fn) {
        if(!this.clientList[key]) {            
            this.clientList[key] = []
        }
       
        this.clientList[key].push({            
            id: id,                         
            fn: fn                          
        })
    },
    
    // 發(fā)布消息(發(fā)布函數(shù)), 依次通知訂閱者
    trigger: function () {
        var key = Array.prototype.shift.call(arguments),
            fns = this.clientList[key];
        
        if(!fns || fns.length == 0) {
            return false;                                   
        }
        
        for(var i = 0; i< fns.length; i++) {
             fns[i].fn.apply(this, arguments);
        }
    }
}

再定義一個(gè)安裝發(fā)布-訂閱的函數(shù)installPublishSubscribeEvent,這個(gè)函數(shù)可以給所有對象都動(dòng)態(tài)安裝發(fā)布-訂閱功能:

var installPublishSubscribeEvent = function(obj) {
    for(var i in publishSubscribeEvent) {
        obj[i] = publishSubscribeEvent[i];
    }
}

再來測試一番,我們給文章對象 sgArticleSystem 動(dòng)態(tài)添加發(fā)布-訂閱功能:

var sgArticleSystem = {};

installPublishSubscribeEvent(sgArticleSystem ); 

// 張三訂閱文章A動(dòng)態(tài)
sgArticleSystem.listen("articleA", 3, function(articleTitle, content) { 
    console.log("張三您在早前訂閱了文章:articleA");
    console.log("現(xiàn)" + articleTitle+ "有了新動(dòng)態(tài)");
    console.log("內(nèi)容為:" + content);
});

// 李四訂閱文章B動(dòng)態(tài)
sgArticleSystem.listen("articleB", 4, function(articleTitle, content) { 
    console.log("李四您在早前訂閱了文章:articleB");
    console.log("現(xiàn)" + articleTitle+ "有了新動(dòng)態(tài)");
    console.log("內(nèi)容為:" + content);
});

// 文章系統(tǒng)發(fā)布消息
sgArticleSystem.trigger("articleA", "JavaScript設(shè)計(jì)模式之發(fā)布-訂閱模式", "作者修改了文章");
sgArticleSystem.trigger("articleB", "JavaScript設(shè)計(jì)模式之策略模式", "王五用戶評論了該文章");

好了,該代碼經(jīng)過自測是沒有什么問題的,要是各位看官發(fā)現(xiàn)問題,歡迎反饋?,F(xiàn)在,我們已經(jīng)可以給我們指定的對象安裝發(fā)布-訂閱模式,但是,是不是還少了點(diǎn)什么功能呢?

答案就是少了取消訂閱事件的功能。比如張三突然不想關(guān)注該問題的更新動(dòng)態(tài)了,為了避免繼續(xù)收到問題系統(tǒng)推送過來的消息,張三需要取消之前訂閱的事件?,F(xiàn)在,我們給 publishSubscribeEvent 對象增加 remove 方法。

publishSubscribeEvent.remove = function(key, id) {
    var fns = this.clientList[key];
    
    if(!fns) {                // 如果key對應(yīng)的消息沒人訂閱,直接返回
        return false;
    }
    
    if(!id) {                // 如果沒傳具體的唯一標(biāo)識,則取消key的所有對應(yīng)消息
        fns && (fns.length = 0);
    } else {
        for(var l = fns.length - 1; l >=0; l--) {
            var _id = fns[l].id;
            if(_id == id) {
                fns.splice(l, 1);    // 刪除訂閱者的回調(diào)函數(shù)
            }
        }
    }
}
// 測試代碼
var sgArticleSystem = {};

installPublishSubscribeEvent(sgArticleSystem ); 

// 張三的訂閱
sgArticleSystem.listen("articleA", 3, function(articleTitle, content) { 
    console.log("張三您在早前訂閱了文章:articleA");
    console.log("現(xiàn)" + articleTitle+ "有了新動(dòng)態(tài)");
    console.log("內(nèi)容為:" + content);
});

// 李四的訂閱
sgArticleSystem.listen("articleA", 4, function(articleTitle, content) { 
    console.log("李四您在早前訂閱了文章:articleA");
    console.log("現(xiàn)" + articleTitle+ "有了新動(dòng)態(tài)");
    console.log("內(nèi)容為:" + content);
});

sgArticleSystem.remove("articleA", 3);    // 刪除張三的訂閱
sgArticleSystem.trigger("articleA", "JavaScript設(shè)計(jì)模式之發(fā)布-訂閱模式", "作者修改了文章");

上面的代碼跟原著有所不同,原著是在刪除訂閱的時(shí)候是用對比回調(diào)函數(shù)的,而我是往緩存列表加了一個(gè)唯一的標(biāo)識,用于識別。

至此,我們的發(fā)布-訂閱模式第一部分已完結(jié),歡迎大家收藏評論。

附:
JavaScript設(shè)計(jì)模式之發(fā)布-訂閱模式(觀察者模式)-Part2

JavaScript數(shù)據(jù)結(jié)構(gòu)和算法系列:
JS 棧
JS 隊(duì)列-優(yōu)先隊(duì)列、循環(huán)隊(duì)列

JavaScript設(shè)計(jì)模式系列:
JavaScript設(shè)計(jì)模式之策略模式

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/80801.html

相關(guān)文章

  • JavaScript設(shè)計(jì)模式發(fā)布-訂閱模式察者模式)-Part2

    摘要:設(shè)計(jì)模式與開發(fā)實(shí)踐讀書筆記??创宋恼虑?,建議先看設(shè)計(jì)模式之發(fā)布訂閱模式觀察者模式在中,已經(jīng)介紹了什么是發(fā)布訂閱模式,同時(shí),也實(shí)現(xiàn)了發(fā)布訂閱模式。 《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》讀書筆記。 看此文章前,建議先看JavaScript設(shè)計(jì)模式之發(fā)布-訂閱模式(觀察者模式)-Part1 在Part1中,已經(jīng)介紹了什么是發(fā)布-訂閱模式,同時(shí),也實(shí)現(xiàn)了發(fā)布-訂閱模式。但是,就Part1...

    Charlie_Jade 評論0 收藏0
  • JavaScript設(shè)計(jì)模式發(fā)布-訂閱模式察者模式)-Part2

    摘要:設(shè)計(jì)模式與開發(fā)實(shí)踐讀書筆記??创宋恼虑?,建議先看設(shè)計(jì)模式之發(fā)布訂閱模式觀察者模式在中,已經(jīng)介紹了什么是發(fā)布訂閱模式,同時(shí),也實(shí)現(xiàn)了發(fā)布訂閱模式。 《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》讀書筆記。 看此文章前,建議先看JavaScript設(shè)計(jì)模式之發(fā)布-訂閱模式(觀察者模式)-Part1 在Part1中,已經(jīng)介紹了什么是發(fā)布-訂閱模式,同時(shí),也實(shí)現(xiàn)了發(fā)布-訂閱模式。但是,就Part1...

    chemzqm 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<