JavaScript设计模式 - 订阅发布模式(观察者模式)

var Event = (function() {
            var global = this,    
                Event,
                _default = 'default';

            Event = function() {
                var _create,
                    _listen,
                    _trigger,
                    _remove,
                    _shift = Array.prototype.shift,
                    _unshift = Array.prototype.unshift,
                    namespaceCache = {},
                    each = function(ary, fn) {
                        var ret;
                        for (var 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);
                };

                _trigger = function() {
                    var cache = _shift.call(arguments),
                        key = _shift.call(arguments),
                        args = arguments,
                        _self = this,
                        stack = cache[key];

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

                    return each(stack, function() {
                        return this.apply(_self, args);
                    });
                };

                _remove = function(key, cache, fn) {
                    if (cache[key]) {
                        if (fn) {
                            for (var i = cache[key].length; i >= 0; i--) {
                                if (cache[key][i] === fn) {
                                    cache[key].splice(i, 1);
                                };
                            };
                        } else {
                            cache[key] = [];
                        };
                    };
                };

                _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;
                            },

                            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();
                            }, 

                            remove: function(key, fn) {
                                _remove(key, cache, fn);
                            },

                            one: function(key, fn, last) {
                                _remove(key, cache);
                                this.listen(key, fn, last);
                            }

                        };
                    return namespace ? (namespaceCache[namespace] ? namespaceCache[namespace] : namespaceCache[namespace] = ret) : ret;
                };

                return {

                    create: _create,

                    one: function(key, fn, last) {
                        var event = this.create();
                        event.one(key, fn, last);
                    },

                    remove: function(key, fn) {
                        var event = this.create();
                        event.remove(key, fn);
                    },

                    listen: function(key, fn, last) {
                        var event = this.create();
                        event.listen(key, fn, last);
                    },

                    trigger: function() {
                        var event = this.create();
                        event.trigger.apply(this, arguments);
                    }
                };

            }();

            return Event;
        })();

使用姿势:

        /*// 先发布后订阅
        event.trigger('evt1', 1, 2);
        event.trigger('evt1', 3, 4);    // 都存到offlineStack中去了

        event.listen('evt1', e1);    // 当有listen监听时,遍历offlineStack中的方法,发给第一次的listen
        event.listen('evt1', e2);*/

        /*// 先订阅后发布
        event.listen('evt1', e1);   
        event.listen('evt1', e2);    // 先订阅的事件都存到cache对象中去了

        event.trigger('evt1', 1, 2);    // 每次发布,都会遍历cache对象中对象事件名的数组
        event.trigger('evt1', 3, 4);   */

        /*// 先发布后订阅 listen方法第三个参数可以是last,只有只会去多个trigger中的最后一个
        event.trigger('evt1', 1, 2);    // 1).
        event.trigger('evt1', 3, 4);    // 2). 都存到offlineStack中去了

        event.listen('evt1', e1, 'last');    // 只会收到2).这个trigger*/

        /*// 先订阅后发布再删除然后再发布,会发现evt1事件对象的cache[key]数组中少了e1函数,所以
        // 再次发布只有e2执行了
        event.listen('evt1', e1);   
        event.listen('evt1', e2);   

        event.trigger('evt1', 1, 2);   
        event.remove('evt1', e1);
        event.trigger('evt1', 3, 4);*/

        // 订阅的再多,也只使用一个订阅
        /*// 1). 先订阅后发布
        event.one('evt1', e1);
        event.one('evt1', e2);    // 会使用这个,因为前一个被删了

        event.trigger('evt1', 11, 22);    // 所以会执行两次e2函数
        event.trigger('evt1', 33, 44);*/

        // 2). 先发布后订阅
        /*event.trigger('evt1', 11, 22);    // 所以会执行两次e2函数
        event.trigger('evt1', 33, 44);

        event.one('evt1', e1);    // 会使用这个,因为offlineStack被置为null了
        event.one('evt1', e2);    // 这个不执行了,需要等到下次trigger才会触发,因为e1从cache中删掉了,加入了e2, 如果后面还有one方法以此类推,会删除上一个监听的函数,添加新的监听函数*/

        // 3). 先发布后订阅 one方法的第三个参数last会只接收最后一个trigger
        event.trigger('evt1', 11, 22);   
        event.trigger('evt1', 33, 44);

        event.one('evt1', e2, 'last');
        event.one('evt1', e1, 'last');    

 

posted @ 2017-08-04 18:24  Sorrow.X  阅读(345)  评论(0编辑  收藏  举报