观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。
实现
观察者模式的实现实际上就是使用回调模式,当状态变更时,调用回调通知观察者。
class Subject {
constructor() {
this.observers = [];
}
attach(observer) {
this.observers.push(observer);
}
detach(observer) {
this.observers.forEach((item, i) => {
if (item === observer) {
this.observers.splice(i, 1);
}
});
}
notify() {
this.observers.forEach((observer) => {
observer.update(this);
});
}
}
class observer {
constructor() {}
update() {
console.log("Observer update");
}
}
/* 使用 */
class subSubject extends Subject {
constructor() {
super();
this.state = null;
this.observers = [];
}
getState() {
return this.state;
}
setState(newState) {
this.state = newState;
this.notify();
}
}
class subObserver extends Observer {
constructor() {
super();
this.state = null;
}
// 重写一个具体的update方法
update(subject) {
this.state = subject.getState();
this.work();
}
work() {
console.log("state change callbackFn");
}
}
应用
假设我们拿到请求得到的数据后,有多个模块添加了回调。如果什么都不考虑可能会直接这样写:
// getAddress 异步请求
// 有三个模块 A,B,C 依赖请求的结果
getAddress().then(res => {
const address = res.address;
A.update(address)
B.next(address)
C.change(address)
})
此时如果多了一个模块 D ,同样需要拿到请求结果后进行下一步操作,我们只好去翻请求的代码把 D 模块的调用补上。
getAddress().then(res => {
const address = res.address;
A.update(address)
B.next(address)
C.change(address)
D.init(address)
})
可以看到各个模块和获取地址模块耦合严重,A、B、C 模块有变化或者有新增模块,都需要深入到获取地址的代码去修改。
根据观察者模式的思想代码可以这样写:
const observers = []
// 注册观察者
observers.push(A.update)
observers.push(B.next)
obervers.push(C.change)
getAddress().then(res => {
const address = res.address;
observers.forEach(update => update(address))
})
可以看到,通过观察者模式的思想我们将添加回调的操作解耦了出来。
参考: