javascript 设计模式之发布-订阅模式

302 阅读1分钟
    // 发布-订阅模式的通用实现
    
    //首先把发布订阅的功能提取出来, 放在一个单独的对象内
    
    var event = {
    clientList: [],
    listen: function(key, fn) {
      if (!this.clientList[key]) {
        this.clientList[key] = [];
      }
      this.clientList[key].push(fn); // 订阅的消息添加进缓存列表
    },
    trigger: function() {
      var key = Array.prototype.shift.call(arguments),
        fns = this.clientList[key];
    
      if (!fns || fns.length === 0) {
        // 如果没有绑定对应的消息
        return false;
      }
      for (var i = 0, fn; (fn = fns[i++]); ) {
        fn.apply(this, arguments); // arguments 是 trigger 时带上的参数
      }
    }
    };
    // 取消订阅的事件
    event.remove = function(key, fn) {
    var fns = this.clientList[key];
    if (!fns) { // 如果 key 对应的消息没有被人订阅, 则直接返回
      return false;
    }
    if (!fn) { // 如果没有传入具体的回调函数, 表示需要取消 key 对应消息的所有订阅
      fns && (fns.length = 0);
    } else {
      for (var l = fns.length - 1; l >= 0; l--) { // 反向遍历订阅的回调函数列表
        var _fn = fns[l];
        if (_fn === fn) {
          fns.splice(1, 1); // 删除订阅者的回调函数
        }
      }
    }
    };
    
    // 在定义一个 installEvent 函数 , 这个函数可以给所有的对象都动态安装发布订阅功能
    
    var installEvent = function(obj) {
    for (var i in event) {
      obj[i] = event[i];
    }
    };
    // 再来测试一番, 我们给售楼处对象 saleOffieces 动态增加发布-订阅功能
    var saleOffieces = {};
    installEvent(saleOffieces);
    
    saleOffieces.listen(
    "squareMeter88",
    (fn1 = function(price) {
      // 小明订阅的消息
      console.log("价格price=" + price);
    })
    );
    
    saleOffieces.listen(
    "squareMeter110",
    (fn2 = function(price) {
      // 小红订阅的消息
      console.log("价格price=" + price);
    })
    );
    
    saleOffieces.remove("squareMeter88", fn1);
    saleOffieces.trigger("squareMeter110", 110);