「设计模式」发布订阅模式🍊

247 阅读3分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

发布订阅模式的定义

我们在看一些介绍设计模式的书时,会发现他们介绍观察者模式和发布订阅模式时,都会把这两种模式混成一种来讲(要么以观察者模式,要么以发布订阅模式命名出现)。实际上,发布订阅模式是最常用的一种观察者模式的实现,并且从解耦和重用角度来看,更优于典型的观察者模式。总结来说,发布订阅模式是观察者模式的一种变形,实质上还是属于观察者模式的。

在这里单独拎出来讲,是因为发布订阅模式和传统意义上的观察者模式的确存在不少不同点。发布订阅模式中相比观察者模式,多了个事件通道,事件通道作为调度中心,管理事件的订阅和发布工作,彻底隔绝了订阅与发布的依赖关系,即在订阅事件时,不关心谁发布;发布事件时,不关心谁订阅;这两个动作都只需要关注事件本身。

如果说观察者模式是面向目标对象和观察者编程的,那么发布订阅模式则是面向调度中心编程的。前者耦合了目标对象和观察者;后者解耦了发布和订阅,统一由调度中心管理。

发布订阅模式的应用场景

在实际开发者,发布订阅模式的应用场景有以下:

  • 广泛应用于异步编程中,是一种替代传递回调函数的方案
  • 订阅ajax请求的error、success事件
  • DOM节点上事件函数的绑定与触发
  • 如果想在动画的每一帧完成后做点事情,可以订阅一个事件,在动画的每一帧完成后发布事件

发布订阅模式的优缺点

优点:

  • 灵活,发布和订阅是解耦的,只要引入发布订阅模式的事件通道作为调度中心,发布和订阅相互之间不影响
  • 可扩展性强,每次新增或者减少时,直接调用调度中心提供出来的方法就行了 缺点:
  • 灵活是优点也是缺点,使用不当会造成数据流混乱(即发布和订阅对不上),导致代码不好维护
  • 性能消耗更大,发布订阅模式需要维护单独的事件队列,订阅的事件越多,内存消耗越大

发布订阅模式的实现原理分析

接下来我们分析一下观察者模式的实现步骤:

  • 新建事件通道(EventCenter)作为调度中心
  • 在事件通道中实现订阅事件(listen)、发布通知(trigger)的方法
  • 对事件通道进行实例化,通过事件通道进行订阅并且发布

具体实现的代码

根据上一步的思路写出代码

// 事件通道作为调度中心
var EventCenter = function(){
    this.eventCache = {};
};
// 订阅事件
EventCenter.prototype.listen = function(type, fn) {
    if(!this.eventCache[type]) {
        this.eventCache[type] = [];
    }
    this.eventCache[type].push(fn);
}
// 发布事件
EventCenter.prototype.trigger = function(type, msg) {
    if(!this.eventCache[type]) return false;
    var fns = this.eventCache[type];
    var count = fns.length || 0;
    while(count--) {
        var fn = fns[count];
        fn(msg);
    }
}
// 实例化事件通道
var event = new EventCenter();
// 进行订阅监听
event.listen('click', function(msg) {
    // 发布时执行的逻辑
    console.log('listen:', msg);
});
// 进行发布通知
event.trigger('click', '发布的通知内容');

// 最后控制台输出:
// listen: 发布的通知内容