简介

观察者模式:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式。

而我们前端vue的响应式原理其实就是观察者模式的实现,只不过他是完全解耦的发布订阅者模式;和基础的观察者模式实现上会有不同,原理都是一样的。

观察者模式是为了将重要的部分与辅助部分进行解耦,我们举个例子:

在前端中,我们的滚动条距离就可以理解为一个重要部分,我们监听了scroll事件,并在回调函数中处理了一条特殊操作,比如根据滚动的距离操作header元素显隐。

此时这个代码量很少,我们知道scroll事件是不建议监听太多的,这会影响到页面的性能和用户体验,但是,有一天我们需要增加一个回到顶部的悬浮按钮,他也得根据滚动的距离来控制显隐,于是我们也将它写在上次的事件回调函数里。

然后随着时间的推移,我们需要在回调函数里增加的内容越来越多,成了一个巨型函数,然后你就会发现,这玩意不好维护了,每次的改动都可能会影响到其他的代码运行,而且还会导致QA测试的时候需要进行全量的测试,以避免新的代码导致旧功能失效。

为了解决这个问题,我们将其进行拆分,将滚动的距离作为一个被观察的对象,所有需要根据滚动距离的判断逻辑都是一个个辅助部分。

辅助部分通过观察的对象提供的接口进行订阅,比如传入一个回调函数。

当被观察的对象发生变化时,会遍历都有的订阅函数,依次运行,并传入变化后的值。

角色:

  1. 抽象的目标类:用于规定用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法
  2. 具体的目标类:实现抽象的目标类规定的方法,是具体的订阅发布实现。
  3. 抽象观察者:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体的目标类的更改通知时被调用。
  4. 具体的观察者:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态

注意:

观察者模式是一个一对多的模式,具体我们往下看代码。

代码

//抽象的目标类
abstract class Subject {
  protected list: Array<Observer> = [];

  //订阅的接口
  public subscription(observer: Observer) {
    this.list.push(observer);
  }

  //取消订阅的接口
  public unsubscription(observer: Observer) {
    this.list = this.list.filter((item) => item !== observer);
  }

  //抽象的通知方法
  public abstract notify(): void;
}

//具体的目标类
class MySubject extends Subject {
  private scrollTop: number = 0;

  constructor() {
    super();
    //监听滚动事件
    window.addEventListener("scroll", () => {
      this.scrollTop = window.scrollY;
      this.notify();
    });
  }

  notify() {
    this.list.forEach((observer) => {
      observer.update(this.scrollTop);
    });
  }
}

//抽象的观察者
abstract class Observer {
  //接受通知的接口
  public abstract update(scrollTop: number): void;
}

//具体的观察者
class MyObserver extends Observer {
  public update(scrollTop: number) {
    console.log(scrollTop);
  }
}

//使用
class Client {
  constructor() {
    const mySubject = new MySubject();
    const myObserver = new MyObserver();
    mySubject.subscription(myObserver);
    // window.scrollTo(0, 100);
  }
}

new Client();

你会发现观察者模式是一种一对多的模式,一个数据源对应多个观察者,这是一个松耦合的代码,但是观察者是知道Subject对象存在的,而且必须通过该对象进行订阅。

而vue的发布订阅者模式是完全解耦的,我们不需要通过Subject对象提供的接口进行订阅,而是通过使用中间函数,比如watchcomputed这些来实现的。

而且发布订阅者模式实现了多对多的关系,相对于单一的观察者模式,更适合在一些复杂的环境使用。

观察者与发布订阅者模式的区别

  1. 以结构来分辨模式,发布订阅模式相比观察者模式多了一个调度中心;
  2. 以意图来分辨模式,都是实现了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新,那么他们就是同一种模式;
  3. 发布订阅模式是在观察者模式的基础上做的优化升级。观察者模式是发布订阅模式的一种特殊实现;

vue的发布订阅者的具体代码就不写了,因为比较复杂,有兴趣去看个vue源码视频就行了,虽然vue的那种模式很难,但是观察者模式实现多对多还是可以的,无非就是在subscription订阅的时候和触发notify这些地方多加一些判断而已。

有兴趣可以百度,都有代码例子。

应用场景

观察者模式适合以下几种情形。

  1. 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
  2. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  3. 实现类似广播机制的功能,不需要知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播。
  4. 多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。
分类: 设计模式 标签: 设计模式行为模式观察者模式

评论

暂无评论数据

暂无评论数据

目录