设计模式|观察者模式(Observer Pattern)

初识观察者模式

观察者模式(Observer Pattern)是一种软件设计模式,属于行为型模式。它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。观察者模式也被称为发布-订阅(Publish-Subscribe)模式。在观察者模式中,有两种核心角色:

  1. Subject(主题):它是被观察的对象,它维护一组依赖于它的观察者,并提供添加、删除和通知观察者的方法。
  2. Observer(观察者):它是依赖于主题的对象,当主题状态发生变化时,观察者会得到通知并进行相应的更新。

优缺点

观察者模式的优点包括:

  • 松耦合:主题和观察者之间的关系是松耦合的,使得它们可以相互独立地变化。
  • 可扩展性:可以方便地增加新的观察者,或者修改现有的观察者,而不需要修改主题的代码。
  • 通知机制:观察者只需要订阅主题,一旦主题状态改变,它们就会自动收到通知,无需手动轮询。

观察者模式虽然有许多优点,但也存在一些缺点,包括:

  • 内存泄漏风险:如果观察者未正确移除,或者被持续添加,可能导致内存泄漏问题。因为主题会持有对观察者的引用,如果观察者在不再需要时没有被正确移除,那么观察者将会一直存在于主题的观察者列表中,从而无法被垃圾回收。
  • 性能问题:当主题有大量观察者时,通知所有观察者可能会影响性能,特别是在需要频繁更新的情况下。因为每次状态改变时,都需要遍历观察者列表并通知它们,这可能会导致性能开销。
  • 可能导致意外更新:观察者模式的设计使得主题的状态改变会导致所有观察者的更新。如果观察者之间存在依赖关系,可能会导致意外的更新序列或循环更新,从而引发不必要的复杂性和错误。
  • 主题状态传递困难:当主题需要将状态传递给观察者时,可能会面临一些挑战。因为通知观察者时通常只会传递简单的通知,而不会传递更多的上下文信息。这可能需要观察者主动查询主题以获取更多的信息,从而增加了系统的复杂性。
  • 不适合异步处理:观察者模式通常是同步的,主题状态改变后会立即通知观察者进行更新。这在某些情况下可能会导致问题,特别是在需要异步处理的情况下,例如需要将状态更新推送到远程服务器时,同步通知可能会导致性能问题或阻塞。

总的来说,观察者模式在一些场景下是非常有用的,但在应用时需要注意以上缺点,以避免可能的问题。
观察者模式在实际应用中被广泛采用,例如在 GUI 开发中,当用户与界面交互时,界面可以作为主题,而控制器或其他对象则可以作为观察者,从而实现界面和业务逻辑的解耦。

示例代码(使用 Java 实现)

import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体主题类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

// 观察者接口
interface Observer {
    void update();
}

// 具体观察者类
class ConcreteObserver implements Observer {
    private ConcreteSubject subject;

    public ConcreteObserver(ConcreteSubject subject) {
        this.subject = subject;
        subject.registerObserver(this);
    }

    @Override
    public void update() {
        System.out.println("State updated: " + subject.getState());
    }
}

// 测试
public class ObserverPatternExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        ConcreteObserver observer1 = new ConcreteObserver(subject);
        ConcreteObserver observer2 = new ConcreteObserver(subject);

        // 修改主题状态,观察者将会得到通知并更新
        subject.setState(5);
    }
}

在上面的示例中,ConcreteSubject是一个具体的主题类,它维护了一个状态,并且具有注册、移除观察者和通知观察者的方法。ConcreteObserver是一个具体的观察者类,它实现了观察者接口,并在构造函数中注册到主题中。通过修改主题的状态,观察者会自动更新。

有哪些知名的框架采用了观察者模式

在后端开发和中间件领域,有一些知名的框架或中间件采用了观察者模式,以下是其中的一些例子:

  1. Spring Framework: Spring 框架中的事件机制就是基于观察者模式实现的。当应用程序中的某些事件发生时,例如上下文加载、Bean 初始化完成等,Spring 会发布相应的事件通知,而监听器(观察者)则可以订阅这些事件并执行相应的操作。
  2. Node.js: 虽然 Node.js 在前端开发中更为知名,但它也被广泛应用于后端开发。Node.js 中的事件驱动模型就是基于观察者模式实现的。EventEmitter 类充当主题,而事件监听器则充当观察者,当特定事件发生时,EventEmitter 会通知所有注册的监听器进行处理。
  3. Apache Kafka: Kafka 是一个分布式流处理平台,也是一个消息中间件。它的消息订阅和发布机制就是基于观察者模式实现的。生产者将消息发布到 Kafka 的主题(topic),而消费者则订阅这些主题,当消息到达时,Kafka 会通知所有订阅了该主题的消费者进行消费。
  4. RabbitMQ: RabbitMQ 是一个开源的消息队列中间件,它也使用了观察者模式。生产者将消息发送到消息队列,而消费者则订阅队列并接收消息,当消息到达时,RabbitMQ 会通知所有订阅了该队列的消费者进行消费。
  5. Django 框架: Django 是一个 Python 的后端 Web 框架,它的信号机制就是基于观察者模式实现的。当某些特定事件发生时(如保存对象前后、用户登录等),Django 会发送信号通知,而信号接收器则可以订阅这些信号并执行相应的处理逻辑。

这些都是在后端开发和中间件领域中广泛使用的框架或中间件,它们都使用了观察者模式来实现事件驱动和消息通知等功能。
观察者模式是非常常用的设计模式,它描述了对象一对多依赖关系下,如何通知并更新的机制,这种机制可以用在前端的 UI 与数据映射、后端的请求与控制器映射,平台间的消息通知等大部分场景,无论现实还是程序中,存在依赖且需要通知的场景非常普遍。

常见面试题

在面试中,可能会遇到以下与观察者模式相关的问题,以及相应的答案:

  1. 请解释观察者模式是什么?
    答案: 观察者模式是一种软件设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
  2. 观察者模式中的核心角色有哪些?
    答案: 观察者模式中有两个核心角色:主题(Subject)和观察者(Observer)。主题维护一组依赖于它的观察者,并提供添加、删除和通知观察者的方法;而观察者则依赖于主题,当主题状态发生变化时,观察者会得到通知并进行相应的更新。
  3. 观察者模式和发布-订阅模式有何区别?
    答案: 观察者模式和发布-订阅模式(Pub-Sub)都涉及到对象间的消息通信,但它们之间有一些区别。观察者模式中,主题对象直接通知观察者对象,而发布-订阅模式中,发布者和订阅者之间通过消息代理或中间件进行通信,发布者不直接与订阅者通信。
  4. 如何避免在观察者模式中可能出现的内存泄漏问题?
    答案: 内存泄漏问题可能出现在观察者模式中,特别是在观察者没有正确移除时。为了避免这种问题,可以在主题中使用弱引用来持有观察者,或者在观察者不再需要时手动将其从主题中移除。
  5. 观察者模式的优缺点是什么?
    答案: 观察者模式的优点包括松耦合、可扩展性和通知机制;而缺点包括内存泄漏风险、性能问题、可能导致意外更新等。
  6. 请列举一个实际应用中观察者模式的例子。
    答案: 一个实际应用中观察者模式的例子是电子商务网站中的库存管理系统。库存管理系统是主题,而订单系统、仓库系统等则是观察者,当某个商品的库存数量发生变化时,库存管理系统会通知所有依赖它的观察者更新相关信息,如商品的可售数量、是否需要补货等。
  7. 观察者模式在哪些框架或中间件中得到了应用?
    答案: 观察者模式在许多框架和中间件中得到了应用,例如 Java 的 Swing/AWT、Spring Framework、Node.js、Apache Kafka、RabbitMQ 等。

这些问题可以帮助面试者深入了解观察者模式的概念、应用和实现细节,展现其对软件设计模式的理解和应用能力。

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
观察者模式Observer Pattern)是一种行为型设计模式,它允许一个对象(称为主题或可观察者)在状态变化时通知其他多个对象(称为观察者)。这个模式主要用于解耦主题和观察者,使它们能够独立地进行修改和扩展。 在观察者模式中,主题维护一个观察者列表,可以动态地添加或移除观察者。当主题的状态发生变化时,它会遍历观察者列表,并调用每个观察者的更新方法,将状态变化的信息传递给观察者。观察者可以根据接收到的信息做出相应的操作。 以下是一个简单的示例代码,演示了观察者模式的实现: ```c #include <iostream> #include <vector> // 观察者接口 class Observer { public: virtual void update(int data) = 0; }; // 具体观察者 A class ConcreteObserverA : public Observer { public: void update(int data) override { std::cout << "ConcreteObserverA received: " << data << std::endl; } }; // 具体观察者 B class ConcreteObserverB : public Observer { public: void update(int data) override { std::cout << "ConcreteObserverB received: " << data << std::endl; } }; // 主题 class Subject { private: int data; std::vector<Observer*> observers; public: void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { // 从观察者列表中删除观察者 // ... } void notify() { for (Observer* observer : observers) { observer->update(data); } } void setData(int value) { data = value; notify(); } }; int main() { Subject subject; ConcreteObserverA observerA; ConcreteObserverB observerB; subject.attach(&observerA); subject.attach(&observerB); subject.setData(42); return 0; } ``` 在上述示例中,`Subject` 是主题类,维护了一个观察者列表。`Observer` 是观察者接口,定义了一个 `update` 方法用于接收主题的通知。`ConcreteObserverA` 和 `ConcreteObserverB` 是具体的观察者类,实现了 `update` 方法。 在 `main` 函数中,我们创建了一个主题对象 `subject` 和两个观察者对象 `observerA` 和 `observerB`。通过调用 `attach` 方法,将观察者对象添加到主题的观察者列表中。然后,通过调用 `setData` 方法改变主题的状态,并自动通知所有观察者。 当 `subject.setData(42)` 被调用时,观察者 `observerA` 和 `observerB` 的 `update` 方法会被依次调用,输出相应的信息。 这就是观察者模式的基本实现。通过使用观察者模式,主题和观察者之间的耦合性降低,可以方便地扩展和修改代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello 阿月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值