Javascript实现 设计模式之发布-订阅模式

96
码农随想录
2017.08.25 22:16* 字数 509

前言


一个多月前,面试时被问到发布-订阅模式,面试完就查阅资料学习了下。这篇文章我将记录我对此的理解并用Javascript代码实现发布-订阅模式。

介绍


用一个全局对象,负责模块间的通信,具体落实发布和订阅两种功能。发布者不需要知道订阅者,订阅者不需要知道发布者,发布者能启动功能器使订阅者收到消息,这就足够了

优势


1、统一管理

订阅模式中,可以抽离出调度中心单独成一个文件,可以对一系列的订阅事件进行统一管理。

2、松耦合

发布者不需要知道订阅者的数量,订阅者听得话题或者订阅者是通过什么方式运行的。他们能够相互独立地运行,这样就可以让你分开开发这两部分而不需要担心对状态或实现的任何细微的影响。

缺点


1、状态未知

发布者不知道订阅者的状态,反之亦然,这样的话,你根本不知道在另一端是否会没有问题?

2、不能识别恶意消息

攻击者(恶意的发布者)能够入侵系统并且撕开它。这会导致恶意的消息被发布,订阅者能够获得他们以前并不能获得的消息。

3、关系更新难

更新发布者和订阅者的关系会是一个很难的问题,因为毕竟他们根本不认识对方。

代码实现

1、发布-订阅模块实现
//publish-subscribe.js

var publishEvents = (function () {
    var listen,log,obj, one, remove, trigger, __this;
    obj = {};
    __this = this;
    listen = function( key, eventfn ) {  // 订阅
        var stack, _ref;
        stack = ( _ref = obj[key] ) != null ? _ref : obj[ key ] = [];
        return stack.push( eventfn );
    };
    one = function( key, eventfn ) { //只能被一个订阅者订阅
        remove( key );
        return listen( key, eventfn );
    };
    remove = function( key ) {  // 解除
        var _ref;
        return ( _ref = obj[key] ) != null ? _ref.length = 0 : void 0;
    };
    trigger = function() {   // 发布
        var fn, stack, _i, _len, _ref, key;
        key = Array.prototype.shift.call( arguments );
        stack = ( _ref = obj[ key ] ) != null ? _ref : obj[ key ] = [];
        for ( _i = 0, _len = stack.length; _i < _len; _i++ ) {
            fn = stack[ _i ];
            if( fn == undefined ) return false;
            if ( fn.apply( __this,  arguments ) === false) {
                return false;
            }
        }
    }
    return {
        listen: listen,
        one: one,
        remove: remove,
        trigger: trigger
    }
})();

module.exports = publishEvents;
2、模块使用
//test-publish-subscribe.js

var pubSub = require('./publish-subscribe');

var testStr = 'testStr';

pubSub.listen(testStr, function() {
    console.log('pubSub.listen');
});

setTimeout(function() {
    console.log('1秒后的 pubSub.trigger')
    pubSub.trigger(testStr);
    pubSub.remove(testStr);
}, 1000);

setTimeout(function() {
    console.log('2秒后的 pubSub.trigger');
    pubSub.trigger(testStr);
}, 2000);
3、结果
运行结果

最后

如果有疑问,请下载示例代码,也可以欢迎私信或者留言给我。
如果觉得对你有帮助,请点个👍,谢谢

前端
Web note ad 1