设计模式之发布订阅模式

Posted by franki on November 3, 2018

iterator

发布订阅模式

又被称为观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将得到通知。在js中,我们一般用事件模型来替代传统的发布订阅模式。 现实场景,买房者与售楼处的关系,前者相当于订阅者,后者相当于发布者。订阅者需要知道知道何时有房子出售,订阅者无需每天打电话到售楼处去询问,他们只需要留下手机号码等联系方式。而售楼处也无需每天回答订阅者的咨询,只需要等到有房子可以出售时根据订阅者的联系方式一一通知例如发短信即可。而且发布者还可以在短信上面添加其他信息如单位、价格

// 实例:
var salesOffices = {}; // 定义售楼处
salesOffices.clientList = {}; // 缓存列表
salesOffices.listen = function(key, fn) {
    if (!this.clientList[key]) {this.clientList[key] = [];}
    this.clientList[key].push(fn);
} // 增加订阅

salesOffices.trigger = function() { // 发布消息
    var key = Array.prototype.shift.call(arguments),
            fns = this.client[key];
    if (!fns || fns.length === 0) {
        return false;
    }
    for (var i=0, fn;fn=fns[i++];) {
        fn.apply(this, arguments);
    }
}

salesOffices.listen(square80, function(price){console.log(price: , price);}) // 添加88平米的房子订阅
salesOffices.listen(square110, function(price){console.log(price, price);}); // 添加110平米的房子订阅

salesOffices.trigger(square80, 10000000);// 发布80平米房子的价格
salesOffices.trigger(square110, 10000000);// 发布110平米房子的价格

对象版本的发布订阅模式

var events = {
  clientList: {},
  listen: function(key, fn) {
    if (!this.clientList[key]) {
      this.clientList[key] = [];
    }
    var flag = false;

    for (var i = 0, len = this.clientList[key].length; i < len; i++) {
      if (fn === this.clientList[key][i]) {
        flag = true;
        break;
      }
    }
    if (!flag) {
      this.clientList[key].push(fn);
    }
  },
  trigger: function() {
    var _shift = Array.prototype.shift,
      key = _shift.call(arguments);
    for (var i = 0, fn; (fn = this.clientList[key][i++]); ) {
      fn.apply(this, arguments);
    }
  },
  remove: function(key, fn) {
    if (!fn || fn.length === 0) {
      this.clientList[key].length = 0;
    } else {
      for (var i = this.clientList[key].length; i >= 0; i--) {
        if (this.clientList[key][i] === fn) {
          this.clientList[key].splice(i, 1);
        }
      }
    }
  }
};

发布者可以精确地发送消息给订阅者,订阅者可以只订阅自己感兴趣的事件了。

发布—订阅模式的优点非常明显,一为时间上的解耦,二为对象之间的解耦。它的应用非常 广泛,既可以用在异步编程中,也可以帮助我们完成更松耦合的代码编写。发布—订阅模式还可 以用来帮助实现一些别的设计模式,比如中介者模式。从架构上来看,无论是 MVC 还是 MVVM, 都少不了发布—订阅模式的参与,而且 JavaScript 本身也是一门基于事件驱动的语言。 当然,发布—订阅模式也不是完全没有缺点。创建订阅者本身要消耗一定的时间和内存,而 且当你订阅一个消息后,也许此消息最后都未发生,但这个订阅者会始终存在于内存中。另外, 发布—订阅模式虽然可以弱化对象之间的联系,但如果过度使用的话,对象和对象之间的必要联 系也将被深埋在背后,会导致程序难以跟踪维护和理解。特别是有多个发布者和订阅者嵌套到一 起的时候,要跟踪一个 bug 不是件轻松的事情。