【TS 设计模式完全指南】构建你的专属“通知中心”:深入观察者模式
一、什么是观察者模式?
观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的依赖关系。当一个对象(被称为主题 Subject或发布者 Publisher)的状态发生改变时,所有依赖于它的对象(被称为观察者 Observers或订阅者 Subscribers)都会得到通知并自动更新。
二、观察者模式的核心组件
-
主题接口 (Subject Interface):声明了用于管理观察者的方法,通常包括
subscribe()
,unsubscribe()
, 和notify()
。 -
观察者接口 (Observer Interface):声明了所有具体观察者必须实现的通知方法,通常是
update()
。 -
具体主题 (Concrete Subject):实现了主题接口。它维护着一个观察者列表,并在自身状态改变时,调用
notify()
方法通知所有观察者。 -
具体观察者 (Concrete Observer):实现了观察者接口。在
update()
方法中定义了收到通知后要执行的具体逻辑。
三、示例:实现一个商品到货通知系统
3.1 定义接口 (Interfaces)
首先定义好我们的“合同”——Subject
和 Observer
接口。
// Observer Interface
interface IObserver {
update(subject: ISubject): void;
}
// Subject Interface
interface ISubject {
subscribe(observer: IObserver): void;
unsubscribe(observer: IObserver): void;
notify(): void;
}
-
update
方法传入subject
本身,这样观察者就可以在需要时从中获取更新后的状态。
3.2 创建具体主题 (Concrete Subject)
我们的 Product
类就是具体主题。它管理自己的库存状态和订阅者列表。
// Concrete Subject
class Product implements ISubject {
public readonly name: string;
private observers: IObserver[] = [];
private _inStock: boolean = false;
constructor(name: string) {
this.name = name;
}
get inStock(): boolean {
return this._inStock;
}
// 状态改变的方法
public setStockStatus(status: boolean): void {
console.log(`\n[PRODUCT]:商品 "${this.name}" 的库存状态变为 ${status ? '有货' : '缺货'}.`);
this._inStock = status;
this.notify(); // 状态改变,通知所有观察者!
}
public subscribe(observer: IObserver): void {
const isExist = this.observers.includes(observer);
if (isExist) {
return console.log('Observer has been attached already.');
}
this.observers.push(observer);
console.log(`[SYSTEM]: ${observer.constructor.name} 成功订阅 "${this.name}".`);
}
public unsubscribe(observer: IObserver): void {
const observerIndex = this.observers.indexOf(observer);
if (observerIndex === -1) {
return console.log('Nonexistent observer.');
}
this.observers.splice(observerIndex, 1);
console.log(`[SYSTEM]: ${observer.constructor.name} 已取消订阅.`);
}
public notify(): void {
console.log(`[PRODUCT]: 正在通知所有 ${this.observers.length} 位订阅者...`);
for (const observer of this.observers) {
observer.update(this);
}
}
}
3.3 创建具体观察者 (Concrete Observers)
现在,我们创建UI更新器和邮件服务,它们都是观察者。
// Concrete Observer 1: UI Updater
class UINotifier implements IObserver {
update(subject: ISubject): void {
if (subject instanceof Product) {
console.log(
`[UI]: 收到通知!商品 "${subject.name}" 现在 ${
subject.inStock ? '有货' : '缺货'
},正在更新页面显示...`
);
}
}
}
// Concrete Observer 2: Email Service
class EmailNotifier implements IObserver {
update(subject: ISubject): void {
if (subject instanceof Product && subject.inStock) {
console.log(`[Email]: 收到通知!商品 "${subject.name}" 已到货,正在准备发送邮件...`);
}
}
}
3.4 客户端代码:将一切联系起来
const ps5 = new Product('PlayStation 5');
const ui = new UINotifier();
const emailService = new EmailNotifier();
// 订阅
ps5.subscribe(ui);
ps5.subscribe(emailService);
// 状态变化 -> 缺货 (假设初始为缺货,这里为了演示,手动设置一次)
ps5.setStockStatus(false);
// 此时只会触发UI更新缺货状态,邮件服务因为逻辑判断不会发送邮件
// 关键时刻:到货了!
ps5.setStockStatus(true);
// 此时UI和Email服务都会收到通知并执行相应操作
// 一个用户不再关心了,取消订阅邮件
ps5.unsubscribe(emailService);
// 再次变为缺货
ps5.setStockStatus(false);
// 这次只有UI会收到通知
为了方便大家学习和实践,本文的所有示例代码和完整项目结构都已整理上传至我的 GitHub 仓库。欢迎大家克隆、研究、提出 Issue,共同进步!
📂 核心代码与完整示例: GoF
总结
如果你喜欢本教程,记得点赞+收藏!关注我获取更多JavaScript/TypeScript开发干货