观察者模式与发布订阅模式

108 阅读2分钟

发布订阅模式与观察者模式

观察者模式

观察者模式定义

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。

image-20220912161212609.png

观察者模式代码实现

/**
 * 观察者观察的对象
 */
class Subject {
  observers: Observer[];
​
  constructor() {
    this.observers = [];
  }
​
  // 添加观察者
  add(observer: Observer) {
    observer instanceof Observer && this.observers.push(observer);
  }
​
  // 移除观察者
  remove(observer: Observer) {
    if (observer instanceof Observer) {
      const idx = this.observers.findIndex((i) => i === observer);
      if (idx > -1) {
        this.observers.splice(idx, 1);
        return true;
      }
    }
    return false;
  }
​
  // 通知观察者
  notify() {
    this.observers.forEach((ob) => {
      ob.update();
    });
  }
}
​
/**
 * 观察者
 */
class Observer {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
​
  // 观察的对象发生改变时对应的回调
  update() {
    console.log(
      "this is call back of observer" + this.name + " when the observed subject changes"
    );
  }
}
​
const sub = new Subject();
const ob1 = new Observer("1");
const ob2 = new Observer("2");
const ob3 = new Observer("3");
sub.add(ob1);
sub.add(ob3);
sub.notify();
// this is call back of observer1 when the observed subject changes
// this is call back of observer3 when the observed subject changes
sub.remove(ob1);
sub.notify();
// this is call back of observer3 when the observed subject changes

发布订阅模式

发布订阅模式定义

发布-订阅模式其实是一种依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。订阅者把自己想订阅的事件注册到调度中心(Event Channel),当发布者发布该事件到调度中心,也就是该事件触发时,由调度中心统一调度订阅者注册到调度中心的处理代码。

image-20220912163842151.png

发布订阅模式代码实现

class EventChannel {
  eventList: Map<string, Function[]>;
​
  constructor() {
    this.eventList = new Map();
  }
​
  listen(action: string, fn: Function) {
    const fns = this.eventList.get(action) || [];
    fns.push(fn);
    this.eventList.set(action, fns);
  }
​
  remove(action: string, fn: Function) {
    const fns = this.eventList.get(action);
    if (!fns) {
      return false;
    }
    const idx = fns.findIndex((f) => f === fn);
    if (idx > -1) {
      fns.splice(idx, 1);
      this.eventList.set(action, fns);
      return true;
    }
    return false;
  }
​
  notify(action: string) {
    const fns = this.eventList.get(action);
    fns && fns.forEach((fn) => fn());
  }
}
​
const evtChannel = new EventChannel();
function fnToBeRemoved () {
  console.log('Cephass subscribes action1');
}
evtChannel.listen('action1', function() {
  console.log('Mike subscribes action1');
})
evtChannel.listen('action1', fnToBeRemoved)
evtChannel.listen('action2', function() {
  console.log('Garphy subscribes action2');
})
​
evtChannel.notify('action1');
// Mike subscribes action1
// Cephass subscribes action1
evtChannel.notify('action2');
// Garphy subscribes action2
evtChannel.remove('action1', fnToBeRemoved)
evtChannel.notify('action1');
// Mike subscribes action1

两者区别

订阅发布模式优点

  • 发布者和订阅者是解耦的,只要引入订阅发布模式的事件中心,无论在何处都可以发布订阅。同时订阅发布者相互之间不影响。

订阅发布模式缺点

  • 使用不当会造成数据流混乱,导致代码不好维护。
  • 性能消耗更大,订阅发布模式需要维护事件列队,订阅的事件越多,内存消耗越大。

观察者模式优点

  • 代码逻辑清晰,容易维护。

观察者模式缺点

  • 相比订阅发布模式,目标和观察者是耦合在一起。