摘要:最常見的觀察者模式事件監聽器這是最簡單最普通的一種觀察者模式,除此以外還有等。動畫在動畫中廣泛使用了觀察者模式,動畫的開始完成暫停等,都需要觀察者來確定物體的行為和狀態。參考資料設計模式發布訂閱模式
1. 最常見的觀察者模式Javascript活躍在事件驅動的環境中,比如鼠標的響應、事件的回調、網絡的請求等,觀察者模式又稱發布者-訂閱者(publisher-subscriber)模式,是處理對象及其行為和狀態之間的關系,管理人與任務之間的關系。
document.body.addEventListener("click", function () { console.log("you clicked me, poor guy!") });
這是最簡單最普通的一種觀察者模式,除此click 以外還有load、blur、drag、focus、mouseover、等。事件監聽器(listener)有別于事件處理器(handler),在事件監聽器中,一個事件可以關聯多個監聽器,每個監聽器獨立處理監聽到的消息;事件處理器是執行處理事件發生后的關聯函數,一種事件是能有一個處理函數:
var dom = $(".dom"); var listener1 = function(e){ //do one thing } var listener2 = function(e){ //do another thing } addEvent(dom,"click",listener1); addEvent(dom,"click",listener2);
在這個事件監聽器的例子中,listener1和listener2 都是dom元素的監聽器,當dom被點擊時,都會執行各自的函數;
var dom = document.getElementById("dom"); var handler1 = function(e){ //do one thing } var handler2 = function(e){ //do another thing } dom.onclick = handler1; dom.onclick = handler2;
在這個事件處理器的例子中,handler1不會被執行,只執行handler2,是一次賦值的操作。
1.2 動畫在動畫中廣泛使用了觀察者模式,動畫的開始、完成、暫停等,都需要觀察者來確定物體的行為和狀態。
//定義動畫 var Animation = function(){ this.onStart = new Publisher; //關于Publisher的設計將在1.3節介紹 this.onComplete = new Publisher; this.onTween = new Publisher; } //定義一個原型方法 Animation.prototype.look = function(){ this.onStart.deliver("animation started!"); this.onTween.deliver("animation is going on!"); this.onComplete.deliver("animation completed!"); }; //實例一個box對象 var box = new Animation(); //定義三個函數作為subscribers var openBox = function(msg){ console.log(msg) } var checkBox = function(msg){ console.log(msg) } var closeBox = function(msg){ console.log(msg) } //訂閱事件 openBox.subscribe(box.onStart); checkBox.subscribe(box.onTween); closeBox.subscribe(box.onComplete); //調用方法 box.look() //animation started! //animation is going on! //animation completed!1.3 觀察者的構建
首先,需要一個發布者。先定義一個構造函數,為其定義一個數組,用以保存訂閱者信息:
function Publisher(){ this.subscribes = []; }
發布者具有發布消息的功能,定義一個deliver的原型函數:
Publisher.prototype.deliver = function(data){ this.subscribes.forEach(function(fn){ fn(data); }); return this; }
接下來構造訂閱方法:
Function.prototype.subscribe = function(publisher){ var that = this; var alreadyExists = publisher.subscribes.some(function(el){ return el === that; }); if(!alreadyExists){ publisher.subscribes.push(this); } return this; }
直接在Function的prototype添加subscribe方法,這樣所有函數都可以調用該方法。這樣就構建完畢了,使用方法參看1.2動畫的用例。
比較直觀的解釋(以onStart為例):當box對象執行look方法時,執行onStart.deliver(),將onStart事件發布出去,廣播通知"animation started!",這個時候,一直在監聽onStart的openBox監聽到該事件發布的信息,打印出來。
這種方式模仿了nodejs的事件處理機制,代碼也比較簡潔:
var scope = (function() { //消息列表 var events = {}; return { //訂閱消息 on:function(name,hander){ var index = 0; //記錄消息時間的索引 if(events[name]){ //消息名已存在,將處理函數放到該消息的事件隊列中 index = events[name].push(hander) - 1; }else{ events[name] = [hander]; } //返回當前消息處理事件的移除函數 return function(){ events[name].splice(index,1); } }, //關閉消息 off:function(name){ if(!events[name]) return; //消息存在,刪除消息 delete events[name]; }, //消息發布 emit:function(name,msg){ //消息不存在,不處理 if(!events[name]) return; //消息存在,將該事件處理隊列中每一個函數都執行一次 events[name].forEach(function(v,i){ v(msg); }); } } })(); var sayHello = scope.on("greeting",function(msg){ console.log("訂閱消息:" + msg); }); var greeting = function(msg){ console.log("發布消息:" + msg); scope.emit("greeting", msg); } greeting("hello Panfen!")1.5 nodejs中觀察者模式的實現方案
nodejs中有events模塊來實現觀察者模式,可參考Nodejs API-Events 談觀察者模式,大多數的模塊都集成了events模塊,所以可以直接使用emit發射事件和on監聽事件,或者像下面這樣先定義一下;
var EventEmitter = require("events").EventEmitter; var life = new EventEmitter(); life.setMaxListeners(11); //設置最大監聽數,默認10 //發布和訂閱sendName life.on("sendName",function(name){ console.log("say hello to "+name); }); life.emit("sendName","jeff"); //發布和訂閱sendName2 function sayBeautiful(name){ console.log(name + " is beautiful"); } life.on("sendName2",sayBeautiful); life.emit("sendName2","jeff");
常用方法:
hasConfortListener :用于判斷發射的事件是否有監聽器
removeListener :移除監聽器
listenerCount :該事件所有監聽器的總數
removeAllListeners :移除事件所有(或某個)的監聽器
1.6 總結觀察者模式建立了推送和收聽的邏輯,適用于希望把人的行為和應用程序的行為分開的場合。舉個例子來說:用戶點擊導航欄的一個tab時,會打開包含更多選項的子菜單,一般會選擇在知道哪個元素的情況下直接監聽這個click事件,這樣做的弊端在于實現了與click事件直接綁在一起。更好的做法是:創建一個可觀察的onTabChange對象,關聯若干觀察者實現。
1.7 參考資料:《Javascript設計模式》
發布(Publish)/ 訂閱(Subscribe)模式
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88182.html
摘要:下面為學習筆記,對觀察者模式做簡單實現。注冊的事件被觸發后需要執行的動作注冊事件及對應的執行動作觸發事件對比執行事件前后的事件列表內容觀察者模式在解決類的耦合中的應用小例子。 這篇筆記主要記錄學習思路及收獲,分享出來拋磚引玉,如有謬誤或優化空間,歡迎交流。 要理解觀察者模式,可以類比vue中的EventBus,其實就是一個全局的觀察者對象($bus),上面有注冊事件($bus.on()...
摘要:總結一下從表面上看觀察者模式里,只有兩個角色觀察者被觀察者而發布訂閱模式,卻不僅僅只有發布者和訂閱者兩個角色,還有第三個角色經紀人存在。參考鏈接觀察者模式發布訂閱模式 做了這么長時間的 菜鳥程序員 ,我好像還沒有寫過一篇關于設計模式的博客...咳咳...意外,純屬意外。所以,我決定,從這一刻起,我要把設計模式在從頭學習一遍,不然都對不起我這 菜鳥 的身份。那這次,就從觀察者模式開始好啦...
摘要:總結一下從表面上看觀察者模式里,只有兩個角色觀察者被觀察者而發布訂閱模式,卻不僅僅只有發布者和訂閱者兩個角色,還有第三個角色經紀人存在。參考鏈接觀察者模式發布訂閱模式 做了這么長時間的 菜鳥程序員 ,我好像還沒有寫過一篇關于設計模式的博客...咳咳...意外,純屬意外。所以,我決定,從這一刻起,我要把設計模式在從頭學習一遍,不然都對不起我這 菜鳥 的身份。那這次,就從觀察者模式開始好啦...
摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環大法了~ 《小分享》JavaScript中數組的那些迭代方法~ ...
摘要:寫代碼容易,寫出優雅的代碼難,寫易于維護的容易擴展的結構清晰的代碼應該是每位開發者努力的目標,而學習設計模式,合理的的使用能讓我們離這個目標更進一步。 寫代碼容易,寫出優雅的代碼難,寫易于維護的、容易擴展的、結構清晰的代碼應該是每位開發者努力的目標,而學習設計模式,合理的的使用能讓我們離這個目標更進一步。最近看了《Javascript設計模式與開發實踐》這本書,一言以蔽之,真不錯的一本...
閱讀 4122·2022-09-16 13:49
閱讀 1398·2021-11-22 15:12
閱讀 1519·2021-09-09 09:33
閱讀 1039·2019-08-30 13:15
閱讀 1720·2019-08-29 15:30
閱讀 654·2019-08-27 10:52
閱讀 2643·2019-08-26 17:41
閱讀 1896·2019-08-26 12:11