观察者模式
观察者可以对不同的主题进行观察,每个观察者需要实现一致的方法名(或通过回调实现观察),观察者与主题存在耦合,每个主题需实现添加、移除、通知等操作
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() { } }
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(); }) } }
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() { } }
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(); }) } }
const pubSub = new PubSub();
pubSub.add('subjectOne', ()=>{ }); pubSub.add('subjectOne', ()=>{ }); pubSub.add('subjectTwo', ()=>{ });
pubSub.notify('subjectOne'); pubSub.notify('subjectTwo');
|