亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

javascript設(shè)計(jì)模式學(xué)習(xí)——觀察者模式

duan199226 / 2307人閱讀

摘要:最常見的觀察者模式事件監(jiān)聽器這是最簡(jiǎn)單最普通的一種觀察者模式,除此以外還有等。動(dòng)畫在動(dòng)畫中廣泛使用了觀察者模式,動(dòng)畫的開始完成暫停等,都需要觀察者來(lái)確定物體的行為和狀態(tài)。參考資料設(shè)計(jì)模式發(fā)布訂閱模式

Javascript活躍在事件驅(qū)動(dòng)的環(huán)境中,比如鼠標(biāo)的響應(yīng)、事件的回調(diào)、網(wǎng)絡(luò)的請(qǐng)求等,觀察者模式又稱發(fā)布者-訂閱者(publisher-subscriber)模式,是處理對(duì)象及其行為和狀態(tài)之間的關(guān)系,管理人與任務(wù)之間的關(guān)系。

1. 最常見的觀察者模式
1.1 事件監(jiān)聽器
document.body.addEventListener("click", function () {
    console.log("you clicked me, poor guy!")
});

這是最簡(jiǎn)單最普通的一種觀察者模式,除此click 以外還有load、blur、drag、focus、mouseover、等。事件監(jiān)聽器(listener)有別于事件處理器(handler),在事件監(jiān)聽器中,一個(gè)事件可以關(guān)聯(lián)多個(gè)監(jiān)聽器,每個(gè)監(jiān)聽器獨(dú)立處理監(jiān)聽到的消息;事件處理器是執(zhí)行處理事件發(fā)生后的關(guān)聯(lián)函數(shù),一種事件是能有一個(gè)處理函數(shù):

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);

在這個(gè)事件監(jiān)聽器的例子中,listener1listener2 都是dom元素的監(jiān)聽器,當(dāng)dom被點(diǎn)擊時(shí),都會(huì)執(zhí)行各自的函數(shù);

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;

在這個(gè)事件處理器的例子中,handler1不會(huì)被執(zhí)行,只執(zhí)行handler2,是一次賦值的操作。

1.2 動(dòng)畫

在動(dòng)畫中廣泛使用了觀察者模式,動(dòng)畫的開始、完成、暫停等,都需要觀察者來(lái)確定物體的行為和狀態(tài)。

//定義動(dòng)畫
var Animation = function(){
    this.onStart = new Publisher;  //關(guān)于Publisher的設(shè)計(jì)將在1.3節(jié)介紹
    this.onComplete = new Publisher;
    this.onTween = new Publisher;
}
//定義一個(gè)原型方法
Animation.prototype.look = function(){
    this.onStart.deliver("animation started!");
    this.onTween.deliver("animation is going on!");
    this.onComplete.deliver("animation completed!");  
};

//實(shí)例一個(gè)box對(duì)象
var box = new Animation();

//定義三個(gè)函數(shù)作為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);

//調(diào)用方法
box.look()

//animation started!
//animation is going on!
//animation completed!
1.3 觀察者的構(gòu)建

首先,需要一個(gè)發(fā)布者。先定義一個(gè)構(gòu)造函數(shù),為其定義一個(gè)數(shù)組,用以保存訂閱者信息:

function Publisher(){
    this.subscribes = [];
}

發(fā)布者具有發(fā)布消息的功能,定義一個(gè)deliver的原型函數(shù):

Publisher.prototype.deliver = function(data){
    this.subscribes.forEach(function(fn){
        fn(data);
    });
    return this;
}

接下來(lái)構(gòu)造訂閱方法:

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方法,這樣所有函數(shù)都可以調(diào)用該方法。這樣就構(gòu)建完畢了,使用方法參看1.2動(dòng)畫的用例。
比較直觀的解釋(以onStart為例):當(dāng)box對(duì)象執(zhí)行look方法時(shí),執(zhí)行onStart.deliver(),將onStart事件發(fā)布出去,廣播通知"animation started!",這個(gè)時(shí)候,一直在監(jiān)聽onStartopenBox監(jiān)聽到該事件發(fā)布的信息,打印出來(lái)。

1.4 另一種構(gòu)建觀察者的方式

這種方式模仿了nodejs的事件處理機(jī)制,代碼也比較簡(jiǎn)潔:

    var scope = (function() {
    //消息列表
    var events = {};
    return {
        //訂閱消息
        on:function(name,hander){
            var index = 0;  //記錄消息時(shí)間的索引
            if(events[name]){  
                //消息名已存在,將處理函數(shù)放到該消息的事件隊(duì)列中
                index = events[name].push(hander) - 1; 
            }else{
                events[name] = [hander];
            }
            //返回當(dāng)前消息處理事件的移除函數(shù)
            return function(){
                events[name].splice(index,1);
            }
        },
        //關(guān)閉消息
        off:function(name){
            if(!events[name]) return;
            //消息存在,刪除消息
            delete events[name];
        },
        //消息發(fā)布
        emit:function(name,msg){
            //消息不存在,不處理
            if(!events[name]) return;
            //消息存在,將該事件處理隊(duì)列中每一個(gè)函數(shù)都執(zhí)行一次
            events[name].forEach(function(v,i){
                v(msg);
            });
        }
    }
})();

var sayHello = scope.on("greeting",function(msg){
    console.log("訂閱消息:" + msg);
});

var greeting = function(msg){
    console.log("發(fā)布消息:" + msg);
    scope.emit("greeting", msg);
}

greeting("hello Panfen!") 
1.5 nodejs中觀察者模式的實(shí)現(xiàn)方案

nodejs中有events模塊來(lái)實(shí)現(xiàn)觀察者模式,可參考Nodejs API-Events 談?dòng)^察者模式,大多數(shù)的模塊都集成了events模塊,所以可以直接使用emit發(fā)射事件和on監(jiān)聽事件,或者像下面這樣先定義一下;

var EventEmitter = require("events").EventEmitter;
var life = new EventEmitter();
life.setMaxListeners(11);       //設(shè)置最大監(jiān)聽數(shù),默認(rèn)10

//發(fā)布和訂閱sendName
life.on("sendName",function(name){
    console.log("say hello to "+name);
});
life.emit("sendName","jeff");

//發(fā)布和訂閱sendName2
function sayBeautiful(name){
    console.log(name + " is beautiful");
}
life.on("sendName2",sayBeautiful);
life.emit("sendName2","jeff");

常用方法:

hasConfortListener :用于判斷發(fā)射的事件是否有監(jiān)聽器

removeListener :移除監(jiān)聽器

listenerCount :該事件所有監(jiān)聽器的總數(shù)

removeAllListeners :移除事件所有(或某個(gè))的監(jiān)聽器

1.6 總結(jié)

觀察者模式建立了推送收聽的邏輯,適用于希望把人的行為和應(yīng)用程序的行為分開的場(chǎng)合。舉個(gè)例子來(lái)說:用戶點(diǎn)擊導(dǎo)航欄的一個(gè)tab時(shí),會(huì)打開包含更多選項(xiàng)的子菜單,一般會(huì)選擇在知道哪個(gè)元素的情況下直接監(jiān)聽這個(gè)click事件,這樣做的弊端在于實(shí)現(xiàn)了與click事件直接綁在一起。更好的做法是:創(chuàng)建一個(gè)可觀察的onTabChange對(duì)象,關(guān)聯(lián)若干觀察者實(shí)現(xiàn)。

1.7 參考資料:

《Javascript設(shè)計(jì)模式》

發(fā)布(Publish)/ 訂閱(Subscribe)模式

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/88182.html

相關(guān)文章

  • javascript設(shè)計(jì)模式察者模式

    摘要:下面為學(xué)習(xí)筆記,對(duì)觀察者模式做簡(jiǎn)單實(shí)現(xiàn)。注冊(cè)的事件被觸發(fā)后需要執(zhí)行的動(dòng)作注冊(cè)事件及對(duì)應(yīng)的執(zhí)行動(dòng)作觸發(fā)事件對(duì)比執(zhí)行事件前后的事件列表內(nèi)容觀察者模式在解決類的耦合中的應(yīng)用小例子。 這篇筆記主要記錄學(xué)習(xí)思路及收獲,分享出來(lái)拋磚引玉,如有謬誤或優(yōu)化空間,歡迎交流。 要理解觀察者模式,可以類比vue中的EventBus,其實(shí)就是一個(gè)全局的觀察者對(duì)象($bus),上面有注冊(cè)事件($bus.on()...

    Tamic 評(píng)論0 收藏0
  • 設(shè)計(jì)模式 -- 察者模式

    摘要:總結(jié)一下從表面上看觀察者模式里,只有兩個(gè)角色觀察者被觀察者而發(fā)布訂閱模式,卻不僅僅只有發(fā)布者和訂閱者兩個(gè)角色,還有第三個(gè)角色經(jīng)紀(jì)人存在。參考鏈接觀察者模式發(fā)布訂閱模式 做了這么長(zhǎng)時(shí)間的 菜鳥程序員 ,我好像還沒有寫過一篇關(guān)于設(shè)計(jì)模式的博客...咳咳...意外,純屬意外。所以,我決定,從這一刻起,我要把設(shè)計(jì)模式在從頭學(xué)習(xí)一遍,不然都對(duì)不起我這 菜鳥 的身份。那這次,就從觀察者模式開始好啦...

    chengtao1633 評(píng)論0 收藏0
  • 設(shè)計(jì)模式 -- 察者模式

    摘要:總結(jié)一下從表面上看觀察者模式里,只有兩個(gè)角色觀察者被觀察者而發(fā)布訂閱模式,卻不僅僅只有發(fā)布者和訂閱者兩個(gè)角色,還有第三個(gè)角色經(jīng)紀(jì)人存在。參考鏈接觀察者模式發(fā)布訂閱模式 做了這么長(zhǎng)時(shí)間的 菜鳥程序員 ,我好像還沒有寫過一篇關(guān)于設(shè)計(jì)模式的博客...咳咳...意外,純屬意外。所以,我決定,從這一刻起,我要把設(shè)計(jì)模式在從頭學(xué)習(xí)一遍,不然都對(duì)不起我這 菜鳥 的身份。那這次,就從觀察者模式開始好啦...

    makeFoxPlay 評(píng)論0 收藏0
  • JS程序

    摘要:設(shè)計(jì)模式是以面向?qū)ο缶幊虨榛A(chǔ)的,的面向?qū)ο缶幊毯蛡鹘y(tǒng)的的面向?qū)ο缶幊逃行┎顒e,這讓我一開始接觸的時(shí)候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續(xù)了解設(shè)計(jì)模式必須要先搞懂面向?qū)ο缶幊?,否則只會(huì)讓你自己更痛苦。 JavaScript 中的構(gòu)造函數(shù) 學(xué)習(xí)總結(jié)。知識(shí)只有分享才有存在的意義。 是時(shí)候替換你的 for 循環(huán)大法了~ 《小分享》JavaScript中數(shù)組的那些迭代方法~ ...

    melody_lql 評(píng)論0 收藏0
  • 學(xué)習(xí)這些設(shè)計(jì)模式,讓你寫出更優(yōu)雅的代碼

    摘要:寫代碼容易,寫出優(yōu)雅的代碼難,寫易于維護(hù)的容易擴(kuò)展的結(jié)構(gòu)清晰的代碼應(yīng)該是每位開發(fā)者努力的目標(biāo),而學(xué)習(xí)設(shè)計(jì)模式,合理的的使用能讓我們離這個(gè)目標(biāo)更進(jìn)一步。 寫代碼容易,寫出優(yōu)雅的代碼難,寫易于維護(hù)的、容易擴(kuò)展的、結(jié)構(gòu)清晰的代碼應(yīng)該是每位開發(fā)者努力的目標(biāo),而學(xué)習(xí)設(shè)計(jì)模式,合理的的使用能讓我們離這個(gè)目標(biāo)更進(jìn)一步。最近看了《Javascript設(shè)計(jì)模式與開發(fā)實(shí)踐》這本書,一言以蔽之,真不錯(cuò)的一本...

    songjz 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

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