使用广播事件来实现模块解耦

模块化开发往往最大的问题是解耦,怎么设计一个低耦合的组件呢?这里我用到的方法是时间总线(eventBus)方法,也可以叫做广播事件,模块之间通过发送广播的方式来实现通信,事件发起者只需要派发事件,而不必关心事件是否被接收(订阅)。

广播事件也是自定义事件的一种,不同于自定义事件,广播事件没有绑定的主体,但是都是通过观察者设计模式来写的代码。
大体的javascript实现代码如下:其中包括一些简单方法没有列出,例如$.isUndefined

var _cache = {};
var broadcast = {
    /**
     * 派发
     * @param  {[type]} type 事件类型
     * @param  {[type]} data 回调数据
     * @return {[type]}      [description]
     */
    fire:function(type, data){
        var listeners = _cache[type],len = 0;
        if(!$.isUndefined(listeners)){
            var args = [].slice.call(arguments);
            args = args.length > 2 ? args.splice(2, args.length-1) : [];
            args = [data].concat(args);

            len = listeners.length;
            for(var i = 0; i<len;i++){
                var listener = listeners[i];
                if(listener && listener.callback) {
                    args = args.concat(listener.args);
                    listener.callback.apply(listener.scope, args);
                }
            }
        }
        return this;
    },
    /**
     * 订阅广播事件
     * @param  {[type]}   types     事件类型,支持,分隔符
     * @param  {Function} callback 回调函数
     * @param  {[type]}   scope    回调函数上下文
     * @return {[type]}            this
     */
    subscribe:function(types, callback, scope){
        types = types || [];
        var args = [].slice.call(arguments);

        if($.isString(types)){
            types = types.split(',');
        }
        var len = types.length;
        if(len===0){
            return this;
        }
        args = args.length > 3 ? args.splice(3, args.length-1) : [];
        for(var i = 0;i<len;i++){
            var type = types[i];
            _cache[type] = _cache[type] || [];
            _cache[type].push({callback:callback,scope:scope,args:args});
        }
        return this;
    },
    /**
     * 退订
     * @param  {[type]}   type     [description]
     * @param  {Function} callback 假如传入则移出传入的监控事件,否则移出全部
     * @return {[type]}            [description]
     */
    unsubscribe:function(type, callback, scope){
        var listeners = _cache[type];
        if (!listeners) {
            return this;
        }
        if(callback){
            var len = listeners.length,
                tmp = [];

            for(var i=0; i<len; i++) {
                var listener = listeners[i];
                if(listener.callback == callback && listener.scope == scope) {
                } else {
                    tmp.push(listener);
                }
            }
            listeners = tmp;
        }else{
            listeners.length = 0;
        }
        return this;
    },
    /**
     * 订阅别名
     * @return {[type]} [description]
     */
    on:function(){
        return this.subscribe.apply(this,arguments);
    },
    /**
     * 退订别名
     * @return {[type]} [description]
     */
    un:function(){
        return this.unsubscribe.apply(this,arguments);
    },
    dispatch:function(){
        return this.fire.apply(this,arguments);
    },

    removeAll:function(){
        _cache = {};
        return this;
    }
};

使用方法:

broadcast.fire('event name', json);
broadcast.on('event name', function(data){
    console.log(data);
});