观察者模式
约 536 字
观察者模式
核心思想
观察者模式允许一个对象将其状态的改变通知其他对象。
典型用例
发布订阅系统
在消息传递、事件总线或服务中,允许多个订阅者监听和响应由发布者发出的消息或事件。
在这个例子中,主题维护了一个观察者列表。观察者可以订阅主题并接收更新。当主题的 notify 方法被调用时,所有订阅的观察者都会收到消息。这种模式允许观察者和主题之间松耦合的交互,是实现事件处理和消息传递系统的有效方式。
// npm run code src/code/design-pattern/observer/publish-subscribe.ts
export {};
// 定义观察者接口
interface Observer {
update(message: string): void;
}
// 定义主题接口
interface Subject {
subscribe(observer: Observer): void;
unsubscribe(observer: Observer): void;
notify(message: string): void;
}
// 创建一个具体的主题类。这个类将维护一个观察者列表,并实现订阅、退订和通知方法
class ConcreteSubject implements Subject {
private observers: Observer[] = [];
subscribe(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index === -1) {
this.observers.push(observer);
}
}
unsubscribe(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
notify(message: string): void {
for (const observer of this.observers) {
observer.update(message);
}
}
}
// 创建一个或多个具体的观察者类
class ConcreteObserver implements Observer {
constructor(private name: string) {}
update(message: string): void {
console.log(`${this.name} received message: ${message}`);
}
}
const subject = new ConcreteSubject();
const observer1 = new ConcreteObserver("Observer 1");
const observer2 = new ConcreteObserver("Observer 2");
const observer3 = new ConcreteObserver("Observer 3");
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.subscribe(observer3);
subject.notify("Hello World!"); // 所有订阅者接收到消息
subject.unsubscribe(observer2);
subject.notify("Another message"); // Observer 2 不会接收到这个消息
GUI事件监听
观察者模式可以用来处理图形用户界面的事件监听,例如按钮点击、鼠标移动或键盘事件,当事件发生时,相关的监听器会被通知。
// npm run code src/code/design-pattern/observer/gui-event-listening.ts
export {};
// 观察者接口
interface Observer {
update: (eventData: string) => void;
}
// 主题类
class Subject {
private observers: Observer[] = [];
// 订阅
public subscribe(observer: Observer): void {
this.observers.push(observer);
}
// 取消订阅
public unsubscribe(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
// 通知所有观察者
protected notify(eventData: string): void {
this.observers.forEach(observer => observer.update(eventData));
}
// 触发事件
public triggerEvent(eventData: string): void {
this.notify(eventData);
}
}
// 具体的观察者:按钮点击监听器
class ButtonClickListener implements Observer {
update(eventData: string) {
console.log(`Button Click Event: ${eventData}`);
}
}
// 具体的观察者:鼠标移动监听器
class MouseMoveListener implements Observer {
update(eventData: string) {
console.log(`Mouse Move Event: ${eventData}`);
}
}
// 具体的观察者:键盘事件监听器
class KeyboardEventListener implements Observer {
update(eventData: string) {
console.log(`Keyboard Event: ${eventData}`);
}
}
// 创建 Subject 实例
const guiEventSubject = new Subject();
// 创建观察者实例
const buttonClickListener = new ButtonClickListener();
const mouseMoveListener = new MouseMoveListener();
const keyboardEventListener = new KeyboardEventListener();
// 订阅事件
guiEventSubject.subscribe(buttonClickListener);
guiEventSubject.subscribe(mouseMoveListener);
guiEventSubject.subscribe(keyboardEventListener);
// 模拟事件触发
guiEventSubject.triggerEvent('Button A clicked');
guiEventSubject.triggerEvent('Mouse moved to position (100, 200)');
guiEventSubject.triggerEvent('Key pressed: Enter');
更新数据模型
在MVC架构中,可以使用观察者模式,在模型数据改变时,通知所有订阅的视图,以便视图可以根据模型的最新状态更新自己。
// npm run code src/code/design-pattern/observer/model-view-controller.ts
export {};
// 观察者接口
interface Observer {
update: (data: any) => void;
}
// 主题类
class Subject {
private observers: Observer[] = [];
// 订阅
public subscribe(observer: Observer): void {
this.observers.push(observer);
}
// 取消订阅
public unsubscribe(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
// 通知所有观察者
protected notify(data: any): void {
this.observers.forEach(observer => observer.update(data));
}
}
// 模型类
class Model extends Subject {
private data: any;
// 设置数据并通知观察者
public setData(newData: any): void {
this.data = newData;
this.notify(this.data);
}
// 获取数据
public getData(): any {
return this.data;
}
}
// 视图类
class View implements Observer {
private model: Model;
constructor(model: Model) {
this.model = model;
this.model.subscribe(this);
}
update(data: any): void {
console.log(`View updated with data: ${JSON.stringify(data)}`);
}
}
// 使用示例
const model = new Model();
const view1 = new View(model);
const view2 = new View(model);
// 更新模型数据
model.setData({ message: "Hello, Observer Pattern!" });
股票价格或游戏状态更新
观察者模式可以用来处理股票市场价格或在线游戏状态更新,这种模式特别适用于需要实时通知订阅者关于某种状态变化的场景。
// npm run code src/code/design-pattern/observer/price-or-status-update.ts
export {};
// 观察者接口
interface Observer {
update: (data: any) => void;
}
// 主题类
class Subject {
private observers: Observer[] = [];
// 订阅
public subscribe(observer: Observer): void {
this.observers.push(observer);
}
// 取消订阅
public unsubscribe(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
// 通知所有观察者
protected notify(data: any): void {
this.observers.forEach(observer => observer.update(data));
}
}
// 股票市场或游戏状态类
class Market extends Subject {
private state: any;
// 设置状态并通知观察者
public setState(newState: any): void {
this.state = newState;
this.notify(this.state);
}
// 获取状态
public getState(): any {
return this.state;
}
}
// 具体的观察者:用户
class User implements Observer {
private name: string;
constructor(name: string) {
this.name = name;
}
update(data: any): void {
console.log(`${this.name} received update: ${JSON.stringify(data)}`);
}
}
// 使用示例
const stockMarket = new Market();
const user1 = new User("Alice");
const user2 = new User("Bob");
// 用户订阅股票市场更新
stockMarket.subscribe(user1);
stockMarket.subscribe(user2);
// 股票市场状态变化
stockMarket.setState({ stock: "AAPL", price: 150 });
stockMarket.setState({ stock: "MSFT", price: 250 });
社交媒体更新
在社交媒体应用中,当用户的状态或关注的话题有更新时,可以使用观察者模式通知所有订阅的用户。
// npm run code src/code/design-pattern/observer/social-media-updates.ts
export {};
// Observer interface
interface Observer {
update(subject: Subject): void;
}
// ConcreteObserver
class SocialMediaUser implements Observer {
constructor(private name: string) {}
update(subject: Subject): void {
console.log(`${this.name} received an update: ${subject.getState()}`);
}
}
// Subject interface
interface Subject {
registerObserver(observer: Observer): void;
removeObserver(observer: Observer): void;
notifyObservers(): void;
getState(): string;
}
// ConcreteSubject
class SocialMediaTopic implements Subject {
private observers: Observer[] = [];
private state: string = '';
registerObserver(observer: Observer): void {
this.observers.push(observer);
}
removeObserver(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index > -1) {
this.observers.splice(index, 1);
}
}
notifyObservers(): void {
for (const observer of this.observers) {
observer.update(this);
}
}
setState(state: string): void {
this.state = state;
this.notifyObservers();
}
getState(): string {
return this.state;
}
}
// 使用示例
const topic = new SocialMediaTopic();
const user1 = new SocialMediaUser("Alice");
const user2 = new SocialMediaUser("Bob");
topic.registerObserver(user1);
topic.registerObserver(user2);
topic.setState("New post about TypeScript!");
处理传感器数据
在物联网(IoT)或智能家居系统中,传感器检测到的数据变化可以通知到依赖这些数据的系统或组件。
// npm run code src/code/design-pattern/observer/sensor-data-processing.ts
export {};
// Observer interface
interface Observer {
update(sensorData: string): void;
}
// ConcreteObserver
class SystemComponent implements Observer {
constructor(private name: string) {}
update(sensorData: string): void {
console.log(`${this.name} received sensor data: ${sensorData}`);
}
}
// Subject interface
interface Subject {
registerObserver(observer: Observer): void;
removeObserver(observer: Observer): void;
notifyObservers(): void;
}
// ConcreteSubject
class Sensor implements Subject {
private observers: Observer[] = [];
private data: string = '';
registerObserver(observer: Observer): void {
this.observers.push(observer);
}
removeObserver(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index > -1) {
this.observers.splice(index, 1);
}
}
notifyObservers(): void {
for (const observer of this.observers) {
observer.update(this.data);
}
}
setData(newData: string): void {
this.data = newData;
this.notifyObservers();
}
}
// 使用示例
const temperatureSensor = new Sensor();
const heatingSystem = new SystemComponent("HeatingSystem");
const coolingSystem = new SystemComponent("CoolingSystem");
temperatureSensor.registerObserver(heatingSystem);
temperatureSensor.registerObserver(coolingSystem);
temperatureSensor.setData("Temperature: 22°C");