0%

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

观察者模式

观察者可以对不同的主题进行观察,每个观察者需要实现一致的方法名(或通过回调实现观察),观察者与主题存在耦合,每个主题需实现添加、移除、通知等操作

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
class Observer {
update() {
//to do...
}
}

class SubjectOne {
_observers = [];
add(observer) {
this._observers.push(observer);
}

remove(observer) {
this._observers = this._observers.filter((ob) => ob !== observer);
}

notify() {
this._observers.forEach(ob => {
ob.update();
})
}
}

class SubjectTwo {
_observers = [];
add(observer) {
this._observers.push(observer);
}

remove(observer) {
this._observers = this._observers.filter((ob) => ob !== observer);
}

notify() {
this._observers.forEach(ob => {
ob.update();
})
}
}

//>>>run
const subjectOne = new SubjectOne();
const subjectTwo = new SubjectTwo();
subjectOne.add(new Observer);
subjectTwo.add(new Observer);

subjectOne.notify();
subjectTwo.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
class Observer {
update() {
//to do...
}
}

class ObserverOp {
_observers = [];
add(observer) {
this._observers.push(observer);
}

remove(observer) {
this._observers = this._observers.filter((ob) => ob !== observer);
}

notify() {
this._observers.forEach(ob => {
ob.update();
})
}
}

class SubjectOne {
_observerOp = new ObserverOp();
add(observer) {
this._observerOp.add(observer);
}

remove(observer) {
this._observerOp.remove(observer);
}

notify() {
this._observerOp.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
class PubSub {
_bus = {};
add(subject, callback) {
if(this._bus[subject]) {
this._bus[subject].push(callback);
} else {
this._bus[subject] = [callback];
}
}

remove(subject, callback) {
const ops = this._bus[subject];
if(!ops || ops.length === 0) {
return;
}

this._bus[subject] = ops.filter(cb => cb !== callback);
}

notify(subject) {
const ops = this._bus[subject];
if(!ops || ops.length === 0) {
return;
}
ops.forEach(cb => {
cb();
})
}
}

//>>>run
const pubSub = new PubSub();
//观察者订阅
pubSub.add('subjectOne', ()=>{ /*todo*/ });
pubSub.add('subjectOne', ()=>{ /*todo other*/ });
pubSub.add('subjectTwo', ()=>{ /*todo*/ });

//发布者发布
pubSub.notify('subjectOne');
pubSub.notify('subjectTwo');