设计模式之观察者模式&发布-订阅模式

一、基础介绍

观察者模式,定义对象间的一种一对多的依赖关系,解决主体对象与观察者之间功能的耦合。

在 JavaScript 中通常使用发布-订阅模式。

设计模式之观察者模式&发布-订阅模式_第1张图片
UML 类图

二、代码实现观察者模式

class Subject {
  constructor() {
    this.observers = [];
  }
  // 订阅
  listen(observer) {
    this.observers.push(observer);
  }
  // 发布
  trigger() {
    this.observers.forEach(observer => {
      observer.update();
    })
  }
  // 移除
  remove(observer) {
    for(let i = this.observers.length - 1; i >= 0; i--) {
      if (this.observers[i] === observer) {
        this.observers.splice(i, 1);
      }
    }
  }
}

class Observer {
  constructor(name, subject) {
    this.name = name;
    this.subject = subject;
    // 订阅
    this.subject.listen(this);
  }
  update() {
    console.log(`${this.name} 监听到了消息`);
  }
}
设计模式之观察者模式&发布-订阅模式_第2张图片
测试代码运行结果

三、代码实现发布-订阅模式

const Event = (function () {
  const eventList = {};
  
  // 订阅
  const listen = function(type, fn) {
    if (!eventList[type]) {
      eventList[type] = [];
    }
    eventList[type].push(fn);
  }
  
  const trigger = function() {
    let type = [].shift.call(arguments);
    let fns = eventList[type];
    if (!fns || fns.length === 0) {
      return false;
    }
    for (let i = 0; i < fns.length; i++) {
      fns[i].apply(this, arguments);
    }
  }

  const remove = function (type, fn) {
    if (!fn) {
      fns && (fns.length = 0);
    } else {
      for(let i = fns.length - 1; i >= 0; i--) {
        if (fns[i] === fn) {
          fns.splice(i, 1);
        }
      }
    }
  }

  return {
    listen,
    trigger,
    remove
  }
})();
设计模式之观察者模式&发布-订阅模式_第3张图片
测试代码运行结果

三、观察者模式和发布-订阅模式的关系

相同点:
都解决了异步的问题。

不同点:

  • 观察者模式中:
    观察者(observer) 和 主体对象(subject) 具有强耦合。
  • 发布-订阅模式中:
    观察者和主体对象之间多了一个消息调度中心。

推荐阅读:
JavaScript Design Patterns
一像素:订阅发布模式和观察者模式真的不一样
MARKSZのBlog:观察者模式VS订阅发布模式

四、拓展

  • 创建命名空间,避免事件类型冲突
  • 实现类似 jquery 的 one(), 即订阅的事件仅执行一次
  • 缓存离线事件

参考

《JavaScript 设计模式与开发实践》曾探
《JavaScript 设计模式》张容铭
Javascript设计模式系统讲解与应用

你可能感兴趣的:(设计模式之观察者模式&发布-订阅模式)