1. 簡介
觀察者模式是一種對象行為模式。它定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。
2. 使用場景
- 當(dāng)一個抽象模型有兩個方面,其中一個方面依賴于另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和復(fù)用。
- 當(dāng)對一個對象的改變需要同時改變其他對象,而不知道具體有多少對象需要被改變。
- 當(dāng)一個對象必須通知其他對象,而它又不能假定其他對象是誰。換言之,不希望這些對象是緊密耦合的。
3. 角色
- 抽象主題(Subject):
它把所有觀察者對象的引用保存到一個聚集里,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象。 - 具體主題(Concrete Subject):
將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。 - 抽象觀察者(Observer):
為所有的具體觀察者定義一個接口,在得到主題通知時更新自己。 - 具體觀察者(Concrete Observer):
實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題狀態(tài)協(xié)調(diào)。
4. 實現(xiàn)

image.png
interface Msg { // Msg 可以按照任意約定的接口格式去約束,這里假設(shè)是如下類型消息
name: string;
value: string;
}
interface Subject {
registerObserver(observer: Observer): void;
removeObserver(observer: Observer): void;
notifyObservers(msg: Msg): void;
}
interface Observer {
update(msg: Msg): void
}
class ConcreteSubject implements Subject {
private observers: Observer[] = [];
private state: object = {};
registerObserver(observer: Observer): void {
this.observers.push(observer);
}
removeObserver(observer: Observer): void {
const index = this.observers.findIndex(val => val === observer);
if (index > -1) {
this.observers.splice(index, 1);
}
}
notifyObservers(msg: Msg): void {
this.observers.forEach(observer => observer.update(msg));
}
setState(name, value): void {
this.state[name] = value;
console.log(`${name}狀態(tài)更新為:${value}`);
console.log('通知所有觀察者');
this.notifyObservers({
name,
value,
});
}
}
class ConcreteObserver implements Observer {
name: string;
constructor(name: string) {
this.name = name;
}
update(msg: Msg): void {
console.log(`${this.name} 觀察到:${msg.name}狀態(tài)更新為:${msg.value}`);
}
}
const concreteSubject = new ConcreteSubject();
const concreteObserver1 = new ConcreteObserver('小王');
const concreteObserver2 = new ConcreteObserver('小明');
concreteSubject.registerObserver(concreteObserver1);
concreteSubject.registerObserver(concreteObserver2);
concreteSubject.setState('天氣', '多云');
concreteSubject.removeObserver(concreteObserver2);
concreteSubject.setState('天氣', '晴');

image.png
這里的 Msg 其實就是一種約定的消息接口,你甚至可以直接使用 Subject,這樣Subject 和 Observer 就是一種雙向關(guān)系(關(guān)聯(lián)和依賴)。另外,這里的 setState 也只是對變更行為的一種抽象而已,你可以在任何事件或者任何時機(jī)通知訂閱者進(jìn)行更新。
5. 小結(jié)
當(dāng)一個對象密切關(guān)注另一個對象的某個狀態(tài)時,就可以使用觀察者模式。它解除了主題和具體觀察者的耦合,讓耦合的雙方都依賴于抽象,而不是依賴具體。
另外,在使用輪詢的地方,我們應(yīng)該先考慮是否可以使用觀察者模式。因為主動觀察是優(yōu)于被動輪詢的。
參考
觀察者模式 - 百度百科
觀察者模式 | 菜鳥教程
圖解23種設(shè)計模式(TypeScript版)——前端必修內(nèi)功心法
Java設(shè)計模式之觀察者模式(Observer Pattern)