代码设计模式——观察者模式
2024-07-12 星期五接上期策略模式之后,现在来介绍观察者模式,实际上我们写代码时经常直接或者间接接触这个模式。实际上发布和订阅消息,以及事件驱动都是观察者模式的应用。它们通常是一对多的形式,即一个主题(可被观察者)和多个观察者组成。映射到现实世界中的应用最明显的就是订报纸,主题就是报纸,观察者就是订阅报纸的人。
假如我们有一个气象站数据,当数据发生变化时,我们需要对应的布告板进行更新,这时我们就可以使用观察者模式。还记得我们之前讲过的设计原则吗?针对接口编程,首先实现主题和观察者的接口,你可以想一下主题和观察者接口需要如何实现会比较好。
// 被观察接口
interface Observable {
// eslint-disable-next-line ts/method-signature-style
notify(): void
// eslint-disable-next-line ts/method-signature-style
register(observer: Observer): void
// eslint-disable-next-line ts/method-signature-style
unregister(observer: Observer): void
}
// 观察者接口
interface Observer<T extends Observable = any> {
// eslint-disable-next-line ts/method-signature-style
update(observable: T): void
}
// 定义显示布告板的接口
interface Display<T> {
// eslint-disable-next-line ts/method-signature-style
display(data: T): void
}
接着就是实现气象站数据和布告板。
// 气象站数据
class WeatherData implements Observable {
private temperature: number = 0
private humidity: number = 0
private pressure: number = 0
private observers: Observer[] = []
// 注册观察者
public register(observer: Observer): void {
this.observers.push(observer)
}
// 取消注册观察者
public unregister(observer: Observer): void {
const index = this.observers.indexOf(observer)
if (index !== -1) {
this.observers.splice(index, 1)
}
}
// 通知观察者
public notify(): void {
for (const observer of this.observers) {
observer.update(this)
}
}
}
// 布告板
class CurrentConditionsDisplay implements Observer<WeatherData>, Display<WeatherData> {
update(observable): void {
this.display(observable)
}
display(data): void {
console.log(`
温度:${data.temperature}
湿度:${data.humidity}
气压:${data.pressure}
`)
}
}
// 布告板
class ForecastDisplay implements Observer<WeatherData>, Display<WeatherData> {
update(observable): void {
this.display(observable)
}
display(data): void {
console.log(`
预报温度:${data.temperature}
预报湿度:${data.humidity}
预报气压:${data.pressure}
`)
}
}
这是一个非常基础的实现,其实我们还可以将observers
属性提取到一个Subject
抽象类中,这样我们可以通过继承Subject
类来管理观察者,这样就可以将观察者的注册和取消注册放在一起了。
如果你对这个模式比较感兴趣,可以尝试使用ReactiveX,这是一个使用充分使用观察者模式的库,并且它支持多种语言。
~ cd ../