首页 元宇宙

C++ 设计模式精讲:观察者模式的原理与实践 (附代码示例)

分类:元宇宙
字数: (9156)
阅读: (5316)
内容摘要:C++ 设计模式精讲:观察者模式的原理与实践 (附代码示例),

在构建复杂系统时,对象间的依赖关系往往会变得错综复杂,直接导致代码的可维护性和可扩展性下降。设计模式中的观察者模式(Observer)正是解决这类问题的利器。通过引入观察者模式,我们可以实现主题(Subject)与观察者(Observer)之间的松耦合,让主题状态的改变自动通知到所有相关的观察者,从而构建出更灵活、更易于维护的系统。

场景重现:告警系统设计

假设我们需要设计一个告警系统。这个系统需要监控各种指标,例如 CPU 利用率、内存使用率、磁盘空间等。当某个指标超过预设的阈值时,系统需要发出告警。告警的方式可能有很多种,例如发送邮件、短信、微信通知等。如果我们将告警逻辑直接写在监控代码中,那么每次新增一种告警方式,都需要修改监控代码,这显然是不可取的。而且告警的粒度可能也会不同,例如某些告警只需要发送给运维人员,而某些告警需要发送给开发人员。

C++ 设计模式精讲:观察者模式的原理与实践 (附代码示例)

观察者模式:底层原理剖析

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象的状态发生改变时,所有依附于它的观察者对象都会收到通知并更新自己。它主要包含以下几个角色:

C++ 设计模式精讲:观察者模式的原理与实践 (附代码示例)
  • 主题(Subject): 维护一个观察者列表,提供添加、删除观察者的方法,并在状态改变时通知所有观察者。
  • 观察者(Observer): 定义一个更新接口,当收到主题的通知时,执行相应的更新操作。
  • 具体主题(ConcreteSubject): 主题的具体实现,负责维护自身的状态,并在状态改变时通知所有观察者。
  • 具体观察者(ConcreteObserver): 观察者的具体实现,实现更新接口,根据主题的状态进行相应的处理。

C++ 代码实现:告警系统示例

下面是一个使用 C++ 实现的告警系统示例:

C++ 设计模式精讲:观察者模式的原理与实践 (附代码示例)
#include <iostream>
#include <vector>
#include <string>

// 观察者接口
class Observer {
public:
    virtual void update(const std::string& message) = 0;
};

// 主题类
class Subject {
private:
    std::vector<Observer*> observers;
public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }

    void detach(Observer* observer) {
        for (auto it = observers.begin(); it != observers.end(); ++it) {
            if (*it == observer) {
                observers.erase(it);
                break;
            }
        }
    }

    void notify(const std::string& message) {
        for (Observer* observer : observers) {
            observer->update(message);
        }
    }
};

// 具体观察者:邮件告警
class EmailAlert : public Observer {
private:
    std::string email;
public:
    EmailAlert(const std::string& email) : email(email) {}
    void update(const std::string& message) override {
        std::cout << "Sending email to " << email << ": " << message << std::endl;
    }
};

// 具体观察者:短信告警
class SMSAlert : public Observer {
private:
    std::string phone;
public:
    SMSAlert(const std::string& phone) : phone(phone) {}
    void update(const std::string& message) override {
        std::cout << "Sending SMS to " << phone << ": " << message << std::endl;
    }
};

// 具体主题:监控系统
class MonitorSystem : public Subject {
private:
    int cpuUsage;
public:
    void setCpuUsage(int usage) {
        cpuUsage = usage;
        if (cpuUsage > 90) {
            notify("CPU usage is over 90%!");
        }
    }
};

int main() {
    MonitorSystem monitor;
    EmailAlert emailAlert("admin@example.com");
    SMSAlert smsAlert("13800000000");

    monitor.attach(&emailAlert);
    monitor.attach(&smsAlert);

    monitor.setCpuUsage(95);

    monitor.detach(&smsAlert);
    monitor.setCpuUsage(80); // 不会发送短信

    return 0;
}

实战避坑:线程安全与内存管理

在使用观察者模式时,需要注意以下几点:

C++ 设计模式精讲:观察者模式的原理与实践 (附代码示例)
  • 线程安全: 如果主题和观察者运行在不同的线程中,需要考虑线程安全问题。可以使用互斥锁(std::mutex)来保护观察者列表,避免并发访问导致的数据竞争。例如,在使用 Nginx 反向代理时,如果 upstream server 的状态变化需要通知多个 worker 进程,就需要考虑进程间通信的线程安全问题。
  • 内存管理: 观察者模式中,主题维护着观察者列表,需要注意观察者的生命周期。如果观察者对象被销毁,但主题仍然持有指向它的指针,就会导致悬挂指针(dangling pointer)。可以使用智能指针(std::shared_ptrstd::weak_ptr)来管理观察者的生命周期,避免内存泄漏。
  • 循环依赖: 需要避免主题和观察者之间出现循环依赖。例如,主题通知观察者更新,观察者又反过来修改主题的状态,导致无限循环。

观察者模式与消息队列

观察者模式和消息队列(如 Kafka、RabbitMQ)都可以实现异步通信,但它们的应用场景有所不同。观察者模式适用于进程内部或单机环境下的对象间通信,而消息队列适用于分布式系统中的服务间通信。例如,在使用宝塔面板搭建网站时,如果需要监控网站的访问量,可以使用观察者模式将访问量数据发送到监控模块;如果需要将访问量数据发送到远程服务器进行分析,则可以使用消息队列。

总而言之,C++ 设计模式中的观察者模式是一种非常有用的设计模式,可以有效地降低对象之间的耦合度,提高系统的可维护性和可扩展性。在实际开发中,可以根据具体的场景选择合适的方式来实现观察者模式,例如可以使用标准库中的 std::functionstd::bind 来简化观察者的实现。例如,可以使用 Lambda 表达式来实现简单的观察者。同时,也要注意线程安全和内存管理等问题,避免引入新的 Bug。

观察者模式的优势总结

  • 松耦合: 主题和观察者之间不需要知道彼此的具体实现,只需要知道彼此的接口即可。
  • 可扩展性: 可以方便地新增或删除观察者,而不需要修改主题的代码。
  • 可重用性: 主题和观察者可以独立地进行测试和重用。

C++ 设计模式精讲:观察者模式的原理与实践 (附代码示例)

转载请注明出处: 夜雨听风

本文的链接地址: http://m.acea1.store/blog/416304.SHTML

本文最后 发布于2026-04-04 14:06:04,已经过了23天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 咸鱼翻身 5 天前
    能否再详细介绍一下观察者模式在 UI 框架中的应用?
  • 鸽子王 1 天前
    不错,结合了实际场景进行讲解,比单纯的概念介绍更容易理解。告警系统的例子很实用!
  • 肝帝 17 小时前
    能否再详细介绍一下观察者模式在 UI 框架中的应用?
  • 猫奴本奴 13 小时前
    不错,结合了实际场景进行讲解,比单纯的概念介绍更容易理解。告警系统的例子很实用!