日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

發布時間:2024/4/17 javascript 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript设计模式之发布-订阅模式(观察者模式)-Part1 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

《JavaScript設計模式與開發實踐》讀書筆記。

發布-訂閱模式又叫觀察者模式,它定義了對象之間的一種一對多的依賴關系。當一個對象的狀態發生改變時,所有依賴它的對象都將得到通知。

例如:在segmentfault我們關注了某一個問題,這個時候可以說是訂閱了這個問題的消息。當該問題有了新的回答、評論的時候,segmentfault系統就會遍歷關注了這個問題的用戶,一次給用戶發消息。

現在看看如何一步步實現發布-訂閱模式。

  • 首先,指定好發布者(如 segmentfault 的 問題系統)

  • 接著,給發布者添加一個緩存列表,用于存放回調函數以便通知訂閱者(問題系統的記錄表)

  • 最后,當發布者發布消息的時候,會遍歷緩存列表,依次觸發里面的回調函數(遍歷記錄表,逐個發消息)

我們還可以在回調函數里面加入一些參數,訂閱者可以接收這些參數,進行各自的處理。

var sgQuestionSystem = {}; // 定義segmentfault的問題系統/* * 緩存列表* clientList: {* key: [* id: <int>, // 唯一標識* fn: null // 存放回調函數* ]* }* */ sgQuestionSystem.clientList = {};/* * 添加訂閱者(訂閱函數),將訂閱的類型與回調函數加入緩存列表* key: 消息的類型* id: 訂閱的唯一標識* fn: 訂閱的回調函數 */ sgQuestionSystem.listen = function(key, id, fn) {if(!this.clientList[key]) { // 若緩存列表沒有該類型的消息,給該類消息初始化this.clientList[key] = []}this.clientList[key].push({ // 將訂閱的id, 回調函數添加到對應的消息列表里id: id, fn: fn }) }// 發布消息(發布函數), 依次通知訂閱者 sgQuestionSystem.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); // arguments是發布消息時附送的參數,去掉了key} }

現在,我們來進行一些簡單的測試:

// 張三訂閱問題A sgQuestionSystem.listen('questionA', 3, function(questionTitle, content) {console.log('張三您在早前訂閱了問題:questionA');console.log('現' + questionTitle + '有了新動態');console.log('內容為:' + content); });// 李四訂閱問題A sgQuestionSystem.listen('questionB', 4, function(questionTitle, content) {console.log('李四您在早前訂閱了問題:questionB');console.log('現' + questionTitle + '有了新動態');console.log('內容為:' + content); })// 問題系統發布消息 sgQuestionSystem.trigger('questionA', '問題A', '王五回答了問題A'); sgQuestionSystem.trigger('questionB', '問題B', '吳六回答了問題B');

至此,我們實現了一個簡單的發布-訂閱模式,訂閱者可以訂閱自己感興趣的事件了。

各位看官,看累了嗎?

看累的話點一下收藏,以便您看續集。若您還是精力充沛,那就繼續擼吧。


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

答案顯然是有的,我們可以將發布-訂閱功能模塊提取出來,放在一個單獨的對象里面:

var publishSubscribeEvent = {/* * 緩存列表* clientList: {* key: [* id: <int>, // 唯一標識* fn: null // 存放回調函數* ]* }* */clientList: {},/* * 添加訂閱者(訂閱函數),將訂閱的類型與回調函數加入緩存列表* key: 消息的類型* id: 訂閱的唯一標識* fn: 訂閱的回調函數*/listen: function(key, id, fn) {if(!this.clientList[key]) { this.clientList[key] = []}this.clientList[key].push({ id: id, fn: fn })},// 發布消息(發布函數), 依次通知訂閱者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);}} }

再定義一個安裝發布-訂閱的函數installPublishSubscribeEvent,這個函數可以給所有對象都動態安裝發布-訂閱功能:

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

再來測試一番,我們給文章對象 sgArticleSystem 動態添加發布-訂閱功能:

var sgArticleSystem = {};installPublishSubscribeEvent(sgArticleSystem ); // 張三訂閱文章A動態 sgArticleSystem.listen('articleA', 3, function(articleTitle, content) { console.log('張三您在早前訂閱了文章:articleA');console.log('現' + articleTitle+ '有了新動態');console.log('內容為:' + content); });// 李四訂閱文章B動態 sgArticleSystem.listen('articleB', 4, function(articleTitle, content) { console.log('李四您在早前訂閱了文章:articleB');console.log('現' + articleTitle+ '有了新動態');console.log('內容為:' + content); });// 文章系統發布消息 sgArticleSystem.trigger('articleA', 'JavaScript設計模式之發布-訂閱模式', '作者修改了文章'); sgArticleSystem.trigger('articleB', 'JavaScript設計模式之策略模式', '王五用戶評論了該文章');

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

答案就是少了取消訂閱事件的功能。比如張三突然不想關注該問題的更新動態了,為了避免繼續收到問題系統推送過來的消息,張三需要取消之前訂閱的事件。現在,我們給 publishSubscribeEvent 對象增加 remove 方法。

publishSubscribeEvent.remove = function(key, id) {var fns = this.clientList[key];if(!fns) { // 如果key對應的消息沒人訂閱,直接返回return false;}if(!id) { // 如果沒傳具體的唯一標識,則取消key的所有對應消息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); // 刪除訂閱者的回調函數}}} } // 測試代碼 var sgArticleSystem = {};installPublishSubscribeEvent(sgArticleSystem ); // 張三的訂閱 sgArticleSystem.listen('articleA', 3, function(articleTitle, content) { console.log('張三您在早前訂閱了文章:articleA');console.log('現' + articleTitle+ '有了新動態');console.log('內容為:' + content); });// 李四的訂閱 sgArticleSystem.listen('articleA', 4, function(articleTitle, content) { console.log('李四您在早前訂閱了文章:articleA');console.log('現' + articleTitle+ '有了新動態');console.log('內容為:' + content); });sgArticleSystem.remove('articleA', 3); // 刪除張三的訂閱 sgArticleSystem.trigger('articleA', 'JavaScript設計模式之發布-訂閱模式', '作者修改了文章');

上面的代碼跟原著有所不同,原著是在刪除訂閱的時候是用對比回調函數的,而我是往緩存列表加了一個唯一的標識,用于識別。

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

附:
JavaScript設計模式之發布-訂閱模式(觀察者模式)-Part2

JavaScript數據結構和算法系列:
JS 棧
JS 隊列-優先隊列、循環隊列

JavaScript設計模式系列:
JavaScript設計模式之策略模式

總結

以上是生活随笔為你收集整理的JavaScript设计模式之发布-订阅模式(观察者模式)-Part1的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。