观察者模式与发布订阅模式的相同点和不同点

169 阅读3分钟

观察者模式与发布订阅模式的相同点和不同点

有人说观察者模式是发布订阅的升级版,也有人说发布订阅是进阶版的观察者模式,但是无论是观察者模式还是发布订阅模式,它们都是定义了对象之间的一种一对多的依赖关系。

观察者模式

当目标对象的状态发生改变时,所有它里面的被观察的对象,都会得到通知,并执行相应的操作。

    // 目标对象类
     function Sub() {
       this.subs = []; // 观察者列表
     }
     Sub.prototype = {
       constructor: Sub,
       add(wather) {
         this.subs.push(wather); // 往观察中添加观察对象
       },
       del(watcher) {
         if (!this.subs.includes(watcher)) return; // 如果被删除的观察对象不存在,直接退出
         // 否则找到其在观察者列表中的索引,将其移除
         let index = this.subs.indexOf(watcher);
         this.subs.splice(index, 1);
       },
       notify() {
         // 通知所有观察的对象进行操作
         this.subs.forEach(watcher => {
           watcher.updata();
         })
       }
     }
     // 观察者类
     function Watch(data) {
       this.data = data; // 确定要被观察的数据
     }
     Watch.prototype = {
       constructor: Watch,
       updata() { // 观察者在接收到目标对象的通知时执行的操作
         console.log('目标对象通知我更新了', this.data);
       }
     }
     // 创建观察者实例(被观察的对象)
     let watcher1 = new Watch('watcher1');
     let watcher2 = new Watch('watcher2');

     // 创建目标对象事件(一个观察者列表)
     let sub = new Sub;
     sub.add(watcher1);
     sub.add(watcher2);

     sub.notify(); // sub通知它列表中的所有观察者进行相应的操作

发布订阅模式

来源于DOM2级事件池,可以同时给同一事件类型行为绑定多个方法,当事件触发,绑定的方法依次被执行。

// 创建事件池类:将事件池作为一个类是为了方便可以在不同地方创建自己的私有事件池
    function Sub() {
      this.eventPool = {}; // 事件池
    }
    Sub.prototype = {
      constructor: Sub,
      add(type, fn) { // 往事件池中添加 指定类型 的 事件
        this.eventPool[type] = this.eventPool[type] || [];
        this.eventPool[type].push(fn)
      },
      remove(type, fn) { // 往事件池中移除 指定类型 的 事件
        let arr = this.eventPool[type];
        if (!arr) return;
        arr = arr.filter(item => item !== fn);
        this.eventPool[type] = arr;

      },
      done(type, ...param) { // 通通知 指定类型 的所有事件依次执行
        let arr = this.eventPool[type];
        if (!arr) return;
        arr.forEach(item => {
          item(...param)
        });
      }
    };
    function f1() {
      console.log(1);
    }
    function f2() {
      console.log(2)
    }
    let s1 = new Sub(); // 创建一个事件池实例 并往事件池中添加指定类型的方法
    s1.add('aa', f1);
    s1.add('aa', f2);
    s1.add('bb', f2);
    s1.done('aa'); // 通知该事件池中的所有 aa 类型事件执行

两种设计模式的相同点和区别:

一、相同点
  • 1、这两种模式都使用了事件池机制(观察者模式中叫观察者列表);
  • 2、两种模式都可以往事件池/观察者列表中添加或删除方法/对象;
  • 3、在发布通知的时候,其事件池/观察者列表中存储的方法/对象都能依次进行相关的操作;
二、不同点
  • 1、观察者模式的事件池机制使用的是数组,而发布订阅使用的是对象;
  • 2、观察者模式需要创建两个类:目标对象类和观察者类;而发布订阅只需要创建一个类:事件池类
  • 3、观察者模式中添加的是观察者Watch类的实例,而发布订阅中添加的是内置类Function的实例;
  • 4、在添加的时候,观察者模式是只添加对象,而发布订阅在添加的时候还指定了添加方法的类型;
  • 5、观察者模式在通知的时候不需要指定类型,而发布订阅需要指定类型。
  • 6、观察者模式中,目标对象(观察者列表)发布时,所有观察对象都会进行相应的操作,而发布订阅只会操作指定类型的方法

看不懂的可以去看这篇文章:baijiahao.baidu.com/s?id=164946…