发布-订阅模式

又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知

在js中,有一种很简单发布订阅模式,也就是DOM事件,addEventListener就可以实现订阅dom节点上的事件,触发事件后就执行回调

1. 自定义事件

实现发布订阅的步骤

  1. 指定好发布者
  2. 为发布者添加一个缓存列表,用以存放回调函数以通知订阅者
  3. 发布消息的时候,发布者会遍历这个缓存列表,依次触发订阅者回调函数。

下面用代码实现一下发布-订阅模式

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
42
43
44
45
// 订阅者回调函数
interface Observers {
[event: string]: Array<Function>
}

// 发布者
let publisher = {
observers: <Observers>{}, // 存放订阅者回调函数
// 增加订阅者
add(event, fn) {
if (!this.observers[event]) {
this.observers[event] = [];
}
this.observers[event].push(fn); // 添加订阅者到缓存列表
},
// 移除订阅者
remove(event, fn) {
let fns = this.observers[event];

if (!fns) { // 如果该事件没有订阅者,则返回
return false;
}
if (!fn) { // 如果没有传入订阅者回调函数,则表示取消该事件的所有订阅者
fns && (fns.length = 0);
} else {
for (let l = fns.length - 1; l >= 0; l--) {
if (fns[l] === fn) {
fns.splice(l, 1);
}
}
}
},
// 发布消息,通知所有订阅者
trigger(event, ...args) {
let fns = this.observers[event];

if (!fns || fns.length === 0) { // 如果没有订阅者,返回false
return false;
}

for (let i = 0, fn; fn = fns[i++];) {
fn.apply(this, args); // 触发订阅者回调函数
}
},
}

如果要实现一个通用的发布-订阅模式

1
2
3
4
5
let installEvent = function(obj) {
for (let i in publisher) {
obj[i] = publisher[i];
}
}

接下来我们来尝试使用一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let salesOffices: any = {};
installEvent(salesOffices);

salesOffices.add('squareMeter88', function(price) {
console.log('小美')
console.log('价格=' + price);
})

salesOffices.add('squareMeter100', function (price) {
console.log('小明')
console.log('价格=' + price);
})

salesOffices.trigger('squareMeter88', 20000); // 小明 20000
salesOffices.trigger('squareMeter100', 30000); // 小美 30000

但是这样salesOffices对象依旧具有耦合度,订阅者必须知道发布者的名字,才能订阅到事件,可以使用全局的发布者Event对象进行发布,就像vue中的eventBus,这样做虽然减少了耦合度,但是消息来自哪个模块,以及会流向哪个模块都是不直观的,容易带来维护性上的问题,并且通过全局的来订阅发布消息,容易造成命名冲突

2.发布-订阅模式的两种模型

  1. 推模型:当一个事件发生后将通知所有订阅者,并把所有的新数据传给他们
  2. 拉模型:当一个事件发生后将通知所有订阅者,每个订阅者将拉取自己需要的数据
    • 可以让订阅者按需获取
    • 但有可能让发布者变成一个“门户大开”的对象,同时增加代码量和复杂度

参考

《javascript设计模式与开发实践》

作者

Liang

发布于

2021-02-02

更新于

2021-12-25

许可协议


评论