观察者与发布订阅者模式

前言

介绍观察者模式发布订阅者模式

观察者模式

观察者模式有两个角色:Subject(目标)用来维护一个 observer 列表、Observer(观察者)在 observer 中定义了一个具体的 update 方法,用来执行相关操作。

整个过程:当某个值发生变化后,Subject 调用 notify 方法,实际上就是循环调用 observer 列表中每个 observer 的 update 方法,并把新的值作为 update 的参数传递进去。就像房东和租客直接直接联系的场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 观察者
class Observer {
constructor() {}
update(val) {}
}
// 观察者列表
class ObserverList {
constructor() {
this.observerList = [];
}
add(observer) {
return this.observerList.push(observer);
}
remove(observer) {
this.observerList = this.observerList.filter(ob => ob != observer);
}
count() {
return this.observerList.length;
}
get(index) {
return this.observerList[index];
}
}
// 目标
class Subject {
constructor() {
this.observers = new ObserverList();
}
addObserver(observer) {
this.observers.add(observer);
}
removeObserver(observer) {
this.observers.remove(observer);
}
notify(...args) {
let obCount = this.observers.count();
for (let index = 0; index < obCount; index++) {
this.observers.get(i).update(...args);
}
}
}

发布订阅者模式

观察者模式中,目标和观察者直接进行交互。发布者订阅者模式中统一用 调度中心 进行处理任务,订阅者发布者互不干扰,一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作就像房东中介租客的场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class PubSub {
constructor() {
this.subscribers = {};
}
subscribe(type, fn) {
if(!Object.prototype.hasOwnProperty.call(this.subscribers, type)) {
this.subscribers[type] = [];
}
this.,subscribers[type].push(fn);
}
unsubscribe(type, fn) {
let listeners = this.subscribers[type];
if(!listeners || !listeners.length) return;
this.subscribers[type] = listeners.filter(v => v !== fn);
}
publish(type, ...args) {
let listeners = this.subscribers[type];
if(!listeners || !listeners.length) return;
listeners.forEach(fn => fn(...args));
}
}
let ob = new PubSub();
ob.subscribe('add', (val) => console.log(val));
ob.publish('add', 1);

总结

  • 观察者模式

    • 由具体目标调度,每个被订阅的目标里面都需要有对观察者的处理,会造成代码的冗余
    • 观察者是知道 Subject 的,Subject 一直保持对观察者进行记录
    • 大多数时候是同步的,比如当事件触发,Subject 就会去调用观察者的方法
  • 发布订阅模式

    • 任务统一由调度中心处理,消除了发布者和订阅者之间的依赖
    • 发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信
    • 大多数时候是异步的(使用消息队列)