js手动封装观察者模式和发布订阅模式

“ 在上一章节中介绍了观察者模式和发布订阅模式的概念和区别,接下来在这篇文章中我将带领大家自己手动封装这两种模式,其实它们的封装是很简单的。”

如果你没有看过上一篇关于观察者模式和发布者模式的概念和区别,那么你可以转至下面这篇链接,然后看完之后再来回顾这篇文章,效果可能会更好哟!
你真的了解观察者模式和发布订阅模式?

1. 观察者模式的封装

在写观察者模式之前,我们需要把思路滤一下:

首先我们应该封装Subject被观察者类、Observer观察者类;
Observer观察者类在初始化时需要设置name值用于区分,接着会有一个update方法,它的作用是监听到变化后处理的逻辑;

Subject被观察者类在初始化的时候设置一个observers的数组,它的作用是用来存储观察者,接着在Subject类中会有add添加观察者方法、remove删除观察者方法、notify通知观察者方法。

接下来就是放代码的时刻:

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* 观察者模式
* 观察者(相当于订阅者)知道被观察者(相当于发布者),并且被观察者也是一直保持对观察者的记录
*/
// 被观察者
class Subject {
constructor () {
this.observers = [];
}
// 添加观察者
add (observer) {
this.observers.push(observer);
}
// 移除观察者
remove (observer) {
let observers = this.observers;
const len = observers.length;
for (let i = 0; i < len; i++) {
if (observers[i] === observer) {
observers.splice(i, 1);
}
}
}
// 通知观察者
notify () {
let observers = this.observers;
const len = observers.length;
for (let i = 0; i < len; i++) {
observers[i].update();
}
}
}

// 观察者
class Observer {
constructor (name) {
this.name = name;
}
update () {
console.log('我是Observer观察者,我被通知了', this.name);
}
}

// test
const subject = new Subject();
const observer1 = new Observer('observer1');
const observer2 = new Observer('observer2');
subject.add(observer1);
subject.add(observer2);
subject.notify();
console.log('----------------------------------------');
subject.remove(observer1);
subject.notify();

/**
* 控制台打印值------------------------------
* 我是Observer观察者,我被通知了 observer1
* 我是Observer观察者,我被通知了 observer2
* ----------------------------------------
* 我是Observer观察者,我被通知了 observer2
*/

2. 发布订阅模式

发布订阅模式其实思路和观察者模式很相似,只是它多了一个第三方的中间调度,我们可以添加一个queue来存储我们的订阅,由于订阅相同的主题可以有多个函数执行,因此我们需要使用数组来存储这些函数。

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
46
47
48
49
class PubSub {
constructor () {
this.queue = {}; // 存储订阅
}
// 添加订阅
subscribe = (event, fn) => {
if (!this.queue[event]) {
this.queue[event] = [];
}
this.queue[event].push(fn);
};
// 发布通知
publish = (event, args) => {
const eventQueue = this.queue[event];
if (!eventQueue) {
return '没有订阅!';
} else {
eventQueue.forEach(item => item(args));
}
};
// 取消订阅
unSubscribe = (event, fn) => {
let eventQueue = this.queue[event];
if (eventQueue) {
this.queue[event] = eventQueue.filter(item => item !== fn);
if (!this.queue[event].length) {
delete this.queue[event];
}
}
};
}
function content(args) {
console.log('发布内容消息' + args);
}
function content2(args) {
console.log('第二种发布内容消息' + args);
}

// test
let p = new PubSub();
p.subscribe('subscribe1', content);
p.subscribe('subscribe1', content2);
p.subscribe('subscribe2', content);
p.unSubscribe('subscribe1', content2);
p.publish('subscribe1', '内容111');
p.publish('subscribe2', '内容222');
// 控制台打印------------------------
// 第一种发布内容消息内容111
// 第一种发布内容消息内容222

感谢segmentfault上的这位作者

JavaScript设计模式——观察者模式 vs 发布订阅模式