JavaScript设计模式「基于ES2024」:行为型模式-观察者模式

40 阅读2分钟

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

// 观察者接口
class Observer {
    update(news) {
        throw new Error('Method not implemented');
    }
}

// 具体观察者
class NewsSubscriber extends Observer {
    #name;

    constructor(name) {
        super();
        this.#name = name;
    }

    update(news) {
        console.log(`${this.#name} received news: ${news}`);
    }
}

// 主题(被观察者)
class NewsPublisher {
    #observers = new Set();
    #latestNews = '';

    addObserver(observer) {
        this.#observers.add(observer);
    }

    removeObserver(observer) {
        this.#observers.delete(observer);
    }

    notifyObservers() {
        for (const observer of this.#observers) {
            observer.update(this.#latestNews);
        }
    }

    setNews(news) {
        this.#latestNews = news;
        this.notifyObservers();
    }
}

// 新闻类别(具体主题)
class SportsNewsPublisher extends NewsPublisher {
    constructor() {
        super();
        this.category = 'Sports';
    }

    publishNews(news) {
        console.log(`\nPublishing sports news: ${news}`);
        this.setNews(`[Sports] ${news}`);
    }
}

class TechnologyNewsPublisher extends NewsPublisher {
    constructor() {
        super();
        this.category = 'Technology';
    }

    publishNews(news) {
        console.log(`\nPublishing technology news: ${news}`);
        this.setNews(`[Technology] ${news}`);
    }
}

// 新闻订阅管理器
class NewsSubscriptionManager {
    #publishers = new Map();

    addPublisher(publisher) {
        this.#publishers.set(publisher.category, publisher);
    }

    subscribe(subscriberName, category) {
        const publisher = this.#publishers.get(category);
        if (publisher) {
            const subscriber = new NewsSubscriber(subscriberName);
            publisher.addObserver(subscriber);
            console.log(`${subscriberName} subscribed to ${category} news`);
        } else {
            console.log(`Category ${category} not available`);
        }
    }

    publishNews(category, news) {
        const publisher = this.#publishers.get(category);
        if (publisher) {
            publisher.publishNews(news);
        } else {
            console.log(`Cannot publish to ${category} - category not found`);
        }
    }
}

// 使用示例
function demonstrateObserver() {
    const manager = new NewsSubscriptionManager();

    const sportsPublisher = new SportsNewsPublisher();
    const techPublisher = new TechnologyNewsPublisher();

    manager.addPublisher(sportsPublisher);
    manager.addPublisher(techPublisher);

    manager.subscribe('Alice', 'Sports');
    manager.subscribe('Bob', 'Technology');
    manager.subscribe('Charlie', 'Sports');
    manager.subscribe('Charlie', 'Technology');

    manager.publishNews('Sports', 'Local team wins championship');
    manager.publishNews('Technology', 'New AI breakthrough announced');
}

demonstrateObserver();

实现思路

  1. Observer:这是观察者接口,定义了 update 方法。

  2. NewsSubscriber 类(具体观察者)

    • 实现了 Observer 接口。
    • 使用私有字段 #name 来存储订阅者名称。
    • 实现了 update 方法来处理接收到的新闻。
  3. NewsPublisher 类(抽象主题)

    • 使用私有字段 #observers(Set)来存储观察者。
    • 提供了添加、移除和通知观察者的方法。
    • 使用私有字段 #latestNews 来存储最新新闻。
  4. SportsNewsPublisherTechnologyNewsPublisher 类(具体主题)

    • 继承自 NewsPublisher
    • 实现了特定类别的新闻发布逻辑。
  5. NewsSubscriptionManager

    • 管理不同类别的新闻发布者。
    • 提供订阅和发布新闻的高层方法。

优点

  • 松耦合:主题和观察者之间是松耦合的,它们可以独立变化。
  • 广播通信:支持一对多的通信模式。
  • 动态关系:可以在运行时动态地建立对象之间的关系。
  • 开闭原则:可以在不修改现有代码的情况下添加新的观察者。