1. 簡介
觀察者模式是一種對象行為模式。它定義對象間的一種一對多的依賴關系悍募,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新洋机。
2. 使用場景
- 當一個抽象模型有兩個方面坠宴,其中一個方面依賴于另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和復用绷旗。
- 當對一個對象的改變需要同時改變其他對象喜鼓,而不知道具體有多少對象需要被改變。
- 當一個對象必須通知其他對象衔肢,而它又不能假定其他對象是誰庄岖。換言之,不希望這些對象是緊密耦合的膀懈。
3. 角色
- 抽象主題(Subject):
它把所有觀察者對象的引用保存到一個聚集里顿锰,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口启搂,可以增加和刪除觀察者對象硼控。 - 具體主題(Concrete Subject):
將有關狀態(tài)存入具體觀察者對象;在具體主題內部狀態(tài)改變時胳赌,給所有登記過的觀察者發(fā)出通知牢撼。 - 抽象觀察者(Observer):
為所有的具體觀察者定義一個接口,在得到主題通知時更新自己疑苫。 - 具體觀察者(Concrete Observer):
實現(xiàn)抽象觀察者角色所要求的更新接口熏版,以便使本身的狀態(tài)與主題狀態(tài)協(xié)調纷责。
4. 實現(xiàn)
image.png
interface Msg { // Msg 可以按照任意約定的接口格式去約束,這里假設是如下類型消息
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 就是一種雙向關系(關聯(lián)和依賴)。另外曲横,這里的 setState 也只是對變更行為的一種抽象而已喂柒,你可以在任何事件或者任何時機通知訂閱者進行更新。
5. 小結
當一個對象密切關注另一個對象的某個狀態(tài)時禾嫉,就可以使用觀察者模式灾杰。它解除了主題和具體觀察者的耦合,讓耦合的雙方都依賴于抽象熙参,而不是依賴具體艳吠。
另外,在使用輪詢的地方孽椰,我們應該先考慮是否可以使用觀察者模式昭娩。因為主動觀察是優(yōu)于被動輪詢的。
參考
觀察者模式 - 百度百科
觀察者模式 | 菜鳥教程
圖解23種設計模式(TypeScript版)——前端必修內功心法
Java設計模式之觀察者模式(Observer Pattern)