C++ 实现观察者模式项目详解

项目背景详细介绍

在软件开发过程中,“观察者模式”是一种非常经典的设计模式,属于行为型设计模式之一。其核心思想是:当一个对象的状态发生变化时,所有依赖于它的对象都能得到通知并自动更新

这种模式的应用场景非常广泛,例如:

  • GUI 框架中,一个按钮被点击时,所有注册的监听器都能收到通知;

  • 游戏引擎中,当角色血量发生变化时,UI 自动更新;

  • 多模块系统中,当核心数据发生变化时,相关模块自动感知变化;

  • 股票行情推送系统中,多个终端订阅同一只股票的价格变动;

  • 消息总线或事件总线系统中,实现低耦合的模块通信。

如果没有观察者模式,我们往往需要手动在每个依赖模块中写很多重复的状态同步代码,模块之间会产生强耦合,维护成本非常高。而观察者模式通过 一对多的消息通知机制,很好地解耦了“发布者”和“订阅者”之间的依赖关系。

本项目的目标是:使用 C++ 编程语言,从零实现一个可复用、可扩展的观察者模式框架,并通过实例演示它在实际开发场景中的应用。


项目需求详细介绍

本项目的功能目标如下:

  1. 实现基本的观察者模式结构

    • 定义“观察者”接口(Observer)

    • 定义“被观察者”或“主题”(Subject)

    • 被观察者可以注册(Attach)、移除(Detach)、通知(Notify)观察者。

  2. 实现一对多通知机制

    • 一个 Subject 可以同时拥有多个 Observer。

    • 当 Subject 状态发生变化时,会自动通知所有已注册的观察者。

  3. 实现观察者响应逻辑

    • 不同观察者可以实现自己的 update() 逻辑。

    • 当接收到通知时,各自根据自身业务逻辑执行动作。

  4. 实现订阅/取消订阅机制

    • 观察者可以动态注册和移除。

    • 支持运行时动态增删观察者,不影响系统整体运行。

  5. 实现简单的演示案例

    • 使用一个简单的“状态变化”场景来演示观察者模式。

    • 比如:一个数据源状态变化时,多个 UI 元素或模块同时收到通知。


相关技术详细介绍

在本项目中,我们会用到以下关键技术和 C++ 编程知识点:

1. 面向对象编程思想(OOP)

观察者模式的基础是面向对象。我们通过接口(纯虚类)定义观察者和被观察者的行为。观察者只需实现接口中的 update() 方法即可接收通知。

2. C++ 虚函数与多态机制

我们通过 C++ 虚函数来实现动态绑定,使不同观察者对象在接收到通知时,能够调用自己对应的逻辑。这也是观察者模式实现的关键之一。

3. 容器与迭代器(std::vector

被观察者内部通过容器(如 std::vector)保存所有观察者指针,实现动态的注册与移除功能。

4. 标准库算法(std::remove + erase

在移除观察者时使用 erase-remove 惯用法,提高代码简洁性和可维护性。

5. 解耦与扩展性

观察者模式的设计目标之一就是 降低模块耦合度
发布者(Subject)不关心观察者的具体类型,也不依赖于它们的实现,从而提高系统的灵活性。


实现思路详细介绍

1. 定义 Observer 接口

我们首先定义一个抽象类(纯虚类)IObserver,其中包含一个纯虚函数 update(int state),用于接收被观察者状态变化时的通知。

2. 定义 Subject 类

Subject 作为被观察者,包含:

  • std::vector<IObserver*> observers 保存所有观察者;

  • attach() 注册观察者;

  • detach() 移除观察者;

  • notify() 通知所有观察者;

  • setState() 修改状态并触发通知。

3. 定义具体的观察者类

通过继承 IObserver,我们可以创建多个具体观察者类。每个观察者在 update() 中实现自己收到通知后的反应逻辑。

4. 触发状态变化

Subject 状态发生变化时,调用 notify(),遍历所有注册的观察者,并依次调用 update() 方法,从而实现一对多的消息广播。

5. 演示功能

main() 函数中,创建一个 Subject 对象和多个 ConcreteObserver 对象。
注册观察者后,修改状态,观察输出结果。


完整实现代码

/*****************************************************
 * 文件名称: observer_pattern.cpp
 * 项目功能: 使用 C++ 实现观察者模式(Observer Pattern)
 * 适用场景: GUI事件监听、消息广播、状态变化通知
 * 作者: ChatGPT
 * 编译环境: C++17
 *****************************************************/

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

/*****************************************************
 * 抽象观察者接口类
 * 每个观察者都需要实现 update() 方法,用于接收通知
 *****************************************************/
class IObserver {
public:
    virtual ~IObserver() = default;
    // state 代表被观察者的最新状态
    virtual void update(int state) = 0;
};

/*****************************************************
 * 被观察者(Subject)
 * 负责维护观察者列表、通知观察者
 *****************************************************/
class Subject {
public:
    // 添加观察者
    void attach(IObserver* observer) {
        observers_.push_back(observer);
    }

    // 移除观察者
    void detach(IObserver* observer) {
        observers_.erase(std::remove(observers_.begin(), observers_.end(), observer), observers_.end());
    }

    // 设置状态并通知所有观察者
    void setState(int newState) {
        state_ = newState;
        notify();
    }

    // 获取当前状态
    int getState() const {
        return state_;
    }

private:
    // 通知所有观察者
    void notify() {
        for (auto* obs : observers_) {
            if (obs) obs->update(state_);
        }
    }

private:
    int state_ = 0;                      // 被观察者状态
    std::vector<IObserver*> observers_;  // 观察者列表
};

/*****************************************************
 * 具体观察者类
 * 不同观察者可以实现不同的 update() 行为
 *****************************************************/
class ConcreteObserver : public IObserver {
public:
    explicit ConcreteObserver(std::string name) : name_(std::move(name)) {}
    void update(int state) override {
        std::cout << "[观察者 " << name_ << "] 收到通知:状态变为 " << state << std::endl;
    }

private:
    std::string name_;
};

/*****************************************************
 * main函数:演示观察者模式的基本用法
 *****************************************************/
int main() {
    // 创建被观察者对象
    Subject subject;

    // 创建两个观察者
    ConcreteObserver observerA("A");
    ConcreteObserver observerB("B");

    // 注册观察者
    subject.attach(&observerA);
    subject.attach(&observerB);

    // 修改状态,所有观察者都会收到通知
    std::cout << "第一次状态更新为 10:" << std::endl;
    subject.setState(10);

    // 移除一个观察者
    subject.detach(&observerB);

    // 再次修改状态,只有 A 会收到通知
    std::cout << "\n第二次状态更新为 20:" << std::endl;
    subject.setState(20);

    return 0;
}

代码详细解读

代码部分 功能说明
IObserver 接口 定义观察者的统一行为标准,确保所有观察者都能响应 update() 通知
Subject 保存观察者列表、状态信息,提供注册、移除和广播通知功能
attach() 方法 将观察者加入列表,实现订阅
detach() 方法 从列表中移除观察者,实现取消订阅
setState() 方法 修改状态,并自动调用 notify() 通知所有观察者
notify() 方法 遍历所有观察者并调用 update(),实现一对多广播
ConcreteObserver 具体观察者实现 update(),打印接收到的状态变化
main() 函数 创建 Subject 与多个观察者,模拟实际运行场景

项目详细总结

本项目通过简洁清晰的 C++ 代码,实现了经典的观察者设计模式。其主要特点包括:

  1. 一对多通知机制
    当 Subject 状态发生变化时,可以同时通知多个 Observer。

  2. 松耦合结构
    Subject 与 Observer 之间仅通过抽象接口通信,彼此不依赖具体实现类,提高了扩展性与可维护性。

  3. 灵活扩展
    可以轻松新增不同类型的观察者,而不必修改 Subject 的代码,符合“开闭原则”。

  4. 代码结构清晰
    使用纯虚类、容器和标准算法实现,逻辑清晰易懂,适合作为项目基础架构的事件机制。


项目常见问题及解答

Q1:观察者对象销毁后忘记移除,会发生什么?

如果 Subject 仍持有已销毁观察者的指针,后续通知会访问非法内存,导致程序崩溃。
✅ 解决方案:

  • 手动在观察者销毁前调用 detach()

  • 或使用智能指针 / 弱引用管理生命周期(可在扩展优化中实现)。

Q2:一个观察者能同时订阅多个 Subject 吗?

可以。观察者可以注册到多个 Subject 上,当任意一个 Subject 状态变化时,观察者都会收到对应的通知。

Q3:如果观察者内部在 update() 中修改了 Subject,会不会造成死循环?

可能会。比如 update() 里再次调用 setState(),从而导致再次 notify()
✅ 建议在设计时防止递归通知,比如增加状态检查、事件队列或标志位。

Q4:线程安全问题怎么处理?

上面的实现没有加锁,多线程环境下可能出现竞态问题。
✅ 可在扩展方向中使用 std::mutex 加锁,保证 attach/detach/notify 的线程安全。


扩展方向与性能优化

  1. 加入智能指针管理
    使用 std::weak_ptrstd::shared_ptr 替代裸指针,自动管理观察者生命周期,避免悬空指针。

  2. 支持 lambda / function 回调
    通过 std::function + std::unordered_map 可以实现无侵入式订阅机制,方便灵活。

  3. 支持多线程安全
    使用 std::mutex 或读写锁保证 attach()detach()notify() 线程安全。

  4. 支持事件过滤
    给每个观察者添加感兴趣的事件类型,实现更精细的订阅机制(如 GUI 系统中)。

  5. 支持订阅 token 自动注销
    通过 RAII(Resource Acquisition Is Initialization)技术,在观察者生命周期结束时自动退订,降低手动管理成本。

  6. 封装为通用事件总线
    将本项目扩展为通用 EventBus 或 MessageBus,可用于大型应用架构中,实现模块间通信。


总结
本项目完整演示了 C++ 实现观察者模式的全过程,从背景、需求到实现和扩展,结构清晰、逻辑严谨。
观察者模式作为设计模式中的基础模块,在实际工程中具有非常高的应用价值,掌握并灵活运用这一模式,可以大大提高系统的可维护性与扩展性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐