跳至主要內容

观察者模式

约 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");

上次编辑于: