Fork me on GitHub

设计模式之发布-订阅模式

发布-订阅模式

 

发布-订阅模式与观察者模式是一个相似的模式,功能上是差不多的。

但观察者模式更合适面向对象的写法,所以在js里看情况使用,如果

不太习惯使用js的面向对象,那么发布-订阅模式就够了。

发布-订阅模式在现今使用的很多,在各大框架,插件都被使用,因为的

它的解耦合,可以大大的提高代码的复用性,比如现在的MVVM框架都有

使用它,或者模块化通信都有使用,如果拜读过jQuery源码的都应该看到

这个模式运用,只是或者你不太甚了解它,为什么它被运用的那么频繁了?

因为代码之间的高度解耦合,现在的都是追求代码复用性高,高质量代码的年代,

所以这个模式很适合,但它也有很大的bug,就是代码追踪可能给你增加难度,

这是很正常的,代码之间的关联关系已经不强,那么他们之间追踪起来就会难。

 

它运用例子场合,如房东与租客,现在的房东大多数都是通过中介把消息推送出去给租客,

所以租客只要和中介有关联就可以知道哪里有房子租。因为中介会租客推送房子的消息。

又或者如微信的关注了公众号,当你微信关闭时是没有收到公众号发布的消息的,但当你上线后

之前离线的发布的消息就会全部推送给你,因为你关注的它,这是个订阅的过程,和发布的过程。

 

所以可以先订阅再发布,也可以先发布再订阅。

 

/*发布-订阅模式*/

    var Event=(function(){
        var event,
            //默认命名空间名
            _default="default";
            event=function(){
                //内部的方法
                var _create,_listen,_trigger,_remove;
                //数组的操作
                var _shift=Array.prototype.shift,
                    _unshift=Array.prototype.unshift;
                //缓存空间
                var cacheSpacename={};
                //循环调用
                var each=function(ary,fn){
                    //判断是否有方法被调用,使用来判断是否离线
                    var ret=false;
                    for(var i=0,l=ary.length;i<l;i++){
                        var n=ary[i];
                        //调用方法,改变this
                        ret=fn.call(n,i,n);
                    }
                    return ret;
                } 
                _listen=function(key,fn,cache){
                    if(!cache[key]){
                        cache[key]=[];
                    }
                    cache[key].push(fn);
                }
                _trigger=function(){
                    var cache=_shift.call(arguments);
                    var key=_shift.call(arguments);
                    var args=arguments;
                    var _self=this;
                    if(!cache[key]){
                        return false;
                    }
                    var ret=each(cache[key],function(){
                        //因为this改变,所以这里的this缓存里的函数
                        this.apply(_self,args);
                    });
                    return ret;
                }
                _remove=function(key,fn,cache){
                    if(!cache[key]||!fn){
                        cache[key]=[];
                        return false;
                    }
                    for(var i=0;i<cache[key].length;i++){
                        if(cache[key][i]==fn){
                            cache[key].splice(i,1);
                            i--;
                        }
                    }
                    return true;
                }
                _create=function(namespace){                    
                        var cache,ret,offlineCache;
                        if(!namespace){
                            namespace=_default;
                        }
                        //缓存空间,重点,使用来存缓存数据和离线数据
                        cache=cacheSpacename[namespace]?cacheSpacename[namespace]:cacheSpacename[namespace]={};
                        offlineCache=cache["offlineCache"]?cache["offlineCache"]:cache["offlineCache"]={};
                        ret={
                            listen:function(key,fn){
                                _listen(key,fn,cache);
                                //判断离线缓存是否存在
                                if(!offlineCache[key]||offlineCache[key].length==0){
                                    return false;
                                }
                                _unshift.call(arguments,offlineCache);
                                _trigger.apply(this,arguments);
                                //离线缓存只是用一次
                                delete offlineCache[arguments[1]];
                            },
                            trigger:function(){
                                var args,
                                _self=this;
                                _unshift.call(arguments,cache);
                                args=arguments;
                                var e=_trigger.apply(_self,args);
                                if(e){
                                    return false;
                                }
                                //使用闭包的访问到离线前的数据参数
                                var fn=function(){
                                    _trigger.apply(_self,args);
                                }
                                //离线缓存
                                if(!offlineCache[args[1]]){
                                    offlineCache[args[1]]=[];
                                }
                                offlineCache[args[1]].push(fn);
                            },
                            remove:function(key,fn){
                                _remove(key,fn,cache);
                            }    
                        };
                        return ret;
                }
                return {
                    create:_create,
                    listen:function(key,fn){
                        var event=this.create();
                            event.listen(key,fn);
                    },
                    trigger:function(){
                        var event=this.create();
                            event.trigger.apply(this,arguments);
                    },
                    remove:function(key,fn){
                        var event=this.create();
                            event.remove(key,fn);
                    }
                }
            }
            return event();
    })();

    /*测试*/
    function a(a){
        console.log(a);
    }
    function b(a){
        console.log("b:"+a);
    }
    Event.trigger("c","default");
    Event.listen("c",a);
    Event.create("zhang").trigger("c","abc");
    Event.create("zhang").listen("c",a);
    Event.create("zhang").trigger("c","abcaa");
    Event.create("zhang").trigger("c","abcxxx");
    Event.create("zhanga").trigger("c","abc");
    Event.create("zhanga").listen("c",a);
    Event.create("zhanga").listen("c",b);
    Event.create("zhanga").remove("c",a);
    Event.create("zhanga").trigger("c","abcxxss");

 

posted @ 2017-06-16 23:36  小数点就是问题  阅读(331)  评论(0编辑  收藏  举报