設(shè)計(jì)模式-發(fā)布-訂閱模式

又叫做觀察者模式,定義對(duì)象之中一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí)候溢谤,所有依賴于它的對(duì)象都將得到通知。

一憨攒、應(yīng)用

  1. 廣泛應(yīng)用于異步編程之中世杀,是一種替代回調(diào)函數(shù)的方案。訂閱一個(gè)事件肝集,發(fā)生操作A(對(duì)操作A監(jiān)聽(tīng))之后瞻坝,事件發(fā)生.
  2. 取代對(duì)象之間硬編碼的通知機(jī)制,一個(gè)對(duì)象不用再顯示的調(diào)用另外一個(gè)對(duì)象的某個(gè)接口杏瞻,讓兩個(gè)對(duì)象松耦合的聯(lián)系在一起所刀,雖然不清楚彼此的細(xì)節(jié)衙荐,但是不影響他們之間相互通信。
1. Dom事件

一種典型的發(fā)布訂閱者模式浮创,一個(gè)事件(‘click忧吟,mousedown等’)對(duì)一個(gè)dom節(jié)點(diǎn)進(jìn)行監(jiān)聽(tīng),操作dom節(jié)點(diǎn)斩披,相應(yīng)的觸發(fā)事件溜族,響應(yīng)函數(shù)執(zhí)行。事件函數(shù)對(duì)dom節(jié)點(diǎn)完全未知垦沉,不用去理會(huì)事件函數(shù)內(nèi)容煌抒,發(fā)布就好。

2. 自定義事件
  • 指定發(fā)布者
  • 給發(fā)布者一個(gè)緩存列表厕倍,一個(gè)對(duì)象由n個(gè)鍵值對(duì)組成,鍵表示事件名,值是一個(gè)由事件處理程序組成的數(shù)組摧玫,相當(dāng)于訂閱者的花名冊(cè)
  • 發(fā)布消息,遍歷緩存列表绑青,依次執(zhí)行訂閱者的回調(diào)函數(shù)诬像。
    自定義事件SF
3. 全局的發(fā)布訂閱模式

問(wèn)題:

  • 每一個(gè)發(fā)布者對(duì)象都有l(wèi)isten和trigger方法,以及一個(gè)緩存列表clientList闸婴,浪費(fèi)資源
  • 發(fā)布者和訂閱者還有一定的耦合關(guān)系:發(fā)布者.listen(“事件名”坏挠,function(){})

所以【對(duì)于全局模式下的訂閱者】:

  • 使用一個(gè)全局的Event對(duì)象來(lái)實(shí)現(xiàn),訂閱者和發(fā)布者不知道相互之間是誰(shuí)邪乍,相當(dāng)于一個(gè)傳遞消息的“中介”:Event.listen("事件名"降狠,function(){})
4. 模塊之間通信
  • 全局模式下的訂閱者而言,兩個(gè)封裝良好的模塊之間的通信是通過(guò)Event對(duì)象來(lái)進(jìn)行的庇楞,比如兩個(gè)模塊都對(duì)Event.count來(lái)進(jìn)行處理榜配,從而實(shí)現(xiàn)模塊之間通信。
  • 這樣的情況之下吕晌,模塊之間的聯(lián)系被隱藏蛋褥,所以需要首先定義好為其他模塊之間通信服務(wù)的暴漏性模塊,他的作用就是暴露出一部分接口睛驳,供其他模塊使用烙心。
5. 全局事件的命名沖突

//全局作用域下的發(fā)布訂閱模式
(function(){
var Event = (function{
    var global = this,
        Modal,
        _default = 'default';

    Event = function(){
        var _listen,
            _trigger,
            _remove,
            _slice = Array.prototype.slice,
            _shift = Array.prototype.shift,
            _unshift = Array.prototype.unshift,
            namespaceCache = {},
            _create,
            find,
            each = function(ary,fn){
                var ret ;
                for(const i = 0,l = ary.length; i < l;i ++){
                    var n = ary[i];
                    ret = fn.call(n,i,n);
                }
                return ret;
            };
        _listen = function(key,fn,cache){
            if(!cache[key]){
                cache[key] = [];
            }
            cache[key].push(fn);
        };
        _remove = function(key,cache,fn){
            if(cache[key]){
                if(fn){
                    for(var i = cache[key].length;i>=0;i--){
                        if(cache[key] === fn){
                            cache[key].splice(i,1);
                        }
                    }
                }else{
                    cache[key] = [];
                }
            }
        };
        _trigger = function(){
            var cache = _shift.call(arguments),
                key = _shift.call(arguments),
                args = arguments,
                _self = this,
                ret,
                stack = cache[key];

            if(!stack || !stack.length){
                return;
            }

            return each(stack,function(){
                return this.apply(_self,args);
            });
        };
        _create = function(namespace){
            var namespace = namespace || _default;
            var cache = {},
                offlineStack = [],
                ret = {
                    listen:function(key,fn,last){
                        _listen(key,fn,cache);
                        if(offlineStack === null){
                            return;
                        }
                        if(last === 'last'){
                            offlineStack.length && offlineStack.pop()();
                        }else{
                            each(offlineStack,function(){
                                this();
                            });
                        }
                        offlineStack = null;
                    },
                    one:function(key,fn,last){
                        _remove(key,cache);
                        this.listen(key,cache,fn);
                    },
                    remove:function(key,fn){
                        _remove(key,cache,fn);
                    },
                    trigger:function(){
                        var fn,
                            args,
                            _self = this;

                        _unshift.call(arguments,cache);
                        args = arguments;
                        fn = function(){
                            return _trigger.apply(_self,args);
                        };
                        if(offlineStack){
                            return offlineStack.push(fn);
                        }
                        return fn;
                    }
                };

                return namespace ? 
                    (namespaceCache[namespace] ? namespaceCache[namespace] : namespaceCache[namespace] = ret) 
                    : ret;
        };
        return {
            create : ,
            one: ,
            remove: ,
            listen:,
            trigger:,
            var event = this.create();
            event.trigger.apply(this,arguments);
        }
    }();
    return Event;
}());

二、遇到的問(wèn)題:

  • 問(wèn)題: 一個(gè)modal組件開(kāi)發(fā)的過(guò)程中乏沸,業(yè)務(wù)邏輯編寫(xiě)完之后淫茵,開(kāi)始進(jìn)行組件化的整合,需要預(yù)留出一個(gè)可被實(shí)例化出一個(gè)組建的構(gòu)造函數(shù)蹬跃,一些開(kāi)放字段匙瘪,一些構(gòu)造函數(shù)的原型方法。要求代碼符合組件化規(guī)范,可復(fù)用丹喻,易擴(kuò)展薄货,松耦合
  • 解決方案: 發(fā)布訂閱模式,一個(gè)組件Modal當(dāng)做發(fā)布者驻啤,里面所有的方法菲驴,預(yù)留參數(shù)當(dāng)做訂閱者,耦合性較松骑冗,封裝又比較嚴(yán)密赊瞬。

....未完待續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市贼涩,隨后出現(xiàn)的幾起案子巧涧,更是在濱河造成了極大的恐慌,老刑警劉巖遥倦,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谤绳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡袒哥,警方通過(guò)查閱死者的電腦和手機(jī)缩筛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)堡称,“玉大人瞎抛,你說(shuō)我怎么就攤上這事∪唇簦” “怎么了桐臊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)晓殊。 經(jīng)常有香客問(wèn)我断凶,道長(zhǎng),這世上最難降的妖魔是什么巫俺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任认烁,我火速辦了婚禮,結(jié)果婚禮上识藤,老公的妹妹穿的比我還像新娘砚著。我一直安慰自己,他們只是感情好痴昧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著冠王,像睡著了一般赶撰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天豪娜,我揣著相機(jī)與錄音餐胀,去河邊找鬼。 笑死瘤载,一個(gè)胖子當(dāng)著我的面吹牛否灾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸣奔,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼墨技,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了挎狸?” 一聲冷哼從身側(cè)響起扣汪,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锨匆,沒(méi)想到半個(gè)月后崭别,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡恐锣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年茅主,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片土榴。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诀姚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鞭衩,到底是詐尸還是另有隱情学搜,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布论衍,位于F島的核電站瑞佩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏坯台。R本人自食惡果不足惜炬丸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜒蕾。 院中可真熱鬧稠炬,春花似錦、人聲如沸咪啡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)撤摸。三九已至毅桃,卻和暖如春褒纲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钥飞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工莺掠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人读宙。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓彻秆,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親结闸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唇兑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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