C++实现设计模式--- 观察者模式 (Observer)

观察者模式 (Observer)

观察者模式 是一种行为型设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,其依赖者(观察者)会收到通知并自动更新。


意图

  • 定义对象之间的一对多依赖关系。
  • 当一个对象状态发生变化时,通知所有依赖于它的对象。

使用场景

  1. 事件驱动系统

    • 如 GUI 程序中的按钮点击事件,按钮通知所有监听器。
  2. 数据变化通知

    • 数据模型的变化需要通知多个视图更新。
  3. 解耦对象之间的依赖

    • 被观察者与观察者通过接口交互,降低了耦合性。

参与者角色

  1. 主题 (Subject)

    • 被观察者,维护观察者列表,并在状态发生变化时通知所有观察者。
  2. 观察者 (Observer)

    • 定义了一个接口,用于接收通知并更新状态。
  3. 具体主题 (ConcreteSubject)

    • 实现具体的主题逻辑,存储状态,并在状态改变时通知观察者。
  4. 具体观察者 (ConcreteObserver)

    • 实现具体的观察者逻辑,接收通知并更新状态。

示例代码

以下代码展示了观察者模式的实现,使用 C++ 的现代特性(如 std::functionstd::vectorshared_ptr)。

cpp 复制代码
#include <iostream>
#include <vector>
#include <memory>
#include <functional>
#include <string>

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

// 具体观察者:实现观察者接口
class ConcreteObserver : public Observer {
private:
    std::string name; // 观察者名称,用于标识

public:
    explicit ConcreteObserver(const std::string& observerName) : name(observerName) {}

    void update(const std::string& message) override {
        std::cout << "观察者 [" << name << "] 收到通知: " << message << std::endl;
    }
};

// 被观察者接口
class Subject {
public:
    virtual ~Subject() = default;
    virtual void attach(std::shared_ptr<Observer> observer) = 0; // 添加观察者
    virtual void detach(std::shared_ptr<Observer> observer) = 0; // 移除观察者
    virtual void notify() = 0;                                   // 通知观察者
};

// 具体被观察者:实现被观察者接口
class ConcreteSubject : public Subject {
private:
    std::vector<std::shared_ptr<Observer>> observers; // 存储观察者的列表
    std::string state;                                // 被观察者的状态

public:
    void attach(std::shared_ptr<Observer> observer) override {
        observers.push_back(observer);
    }

    void detach(std::shared_ptr<Observer> observer) override {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }

    void setState(const std::string& newState) {
        state = newState;
        notify(); // 状态改变时通知所有观察者
    }

    void notify() override {
        for (const auto& observer : observers) {
            observer->update(state);
        }
    }
};

// 客户端代码
int main() {
    auto subject = std::make_shared<ConcreteSubject>();

    // 创建多个观察者
    auto observer1 = std::make_shared<ConcreteObserver>("Observer1");
    auto observer2 = std::make_shared<ConcreteObserver>("Observer2");
    auto observer3 = std::make_shared<ConcreteObserver>("Observer3");

    // 观察者订阅被观察者
    subject->attach(observer1);
    subject->attach(observer2);
    subject->attach(observer3);

    // 修改被观察者的状态,通知观察者
    std::cout << "修改状态为: 状态A" << std::endl;
    subject->setState("状态A");

    // 移除一个观察者
    subject->detach(observer2);

    std::cout << "修改状态为: 状态B" << std::endl;
    subject->setState("状态B");

    return 0;
}

代码解析

1. 观察者接口 (Observer)
  • 定义了一个 update 方法,用于接收通知:
cpp 复制代码
class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(const std::string& message) = 0; // 接收通知
};
2. 具体观察者 (ConcreteObserver)
  • 实现了 Observer 接口,并通过 update 方法更新状态:
cpp 复制代码
class ConcreteObserver : public Observer {
private:
    std::string name;

public:
    explicit ConcreteObserver(const std::string& observerName) : name(observerName) {}

    void update(const std::string& message) override {
        std::cout << "观察者 [" << name << "] 收到通知: " << message << std::endl;
    }
};
3. 被观察者接口 (Subject)
  • 定义了添加、移除观察者的方法,以及通知观察者的 notify 方法:
cpp 复制代码
class Subject {
public:
    virtual ~Subject() = default;
    virtual void attach(std::shared_ptr<Observer> observer) = 0;
    virtual void detach(std::shared_ptr<Observer> observer) = 0;
    virtual void notify() = 0;
};
4. 具体被观察者 (ConcreteSubject)
  • 存储观察者列表,并在状态改变时通知观察者:
cpp 复制代码
class ConcreteSubject : public Subject {
private:
    std::vector<std::shared_ptr<Observer>> observers;
    std::string state;

public:
    void setState(const std::string& newState) {
        state = newState;
        notify(); // 状态改变时通知所有观察者
    }

    void notify() override {
        for (const auto& observer : observers) {
            observer->update(state);
        }
    }
};
5. 客户端
  • 客户端通过 attach 方法订阅观察者,并通过 setState 方法触发通知:
cpp 复制代码
auto subject = std::make_shared<ConcreteSubject>();
auto observer1 = std::make_shared<ConcreteObserver>("Observer1");
subject->attach(observer1);
subject->setState("状态A");

优缺点

优点
  1. 解耦
    • 被观察者与观察者之间通过接口交互,降低了依赖性。
  2. 扩展性强
    • 可以轻松增加新的观察者,而无需修改被观察者代码。
  3. 动态通知
    • 可以在运行时动态添加或移除观察者。
缺点
  1. 通知开销
    • 当观察者较多时,通知的开销可能较大。
  2. 复杂性增加
    • 系统中对象关系变得复杂,可能导致调试困难。

适用场景

  1. 事件驱动系统

    • 如 GUI 程序、游戏引擎等。
  2. 模型-视图结构

    • 数据模型的变化通知视图更新。
  3. 分布式系统

    • 如多个服务监听同一个事件源。

总结

观察者模式通过定义一对多的依赖关系,解决了对象之间的动态联动问题,是事件驱动系统中非常重要的设计模式。

相关推荐
BUG研究员_25 分钟前
责任链设计模式
设计模式
shinelord明30 分钟前
【再谈设计模式】模板方法模式 - 算法骨架的构建者
开发语言·数据结构·设计模式·软件工程
難釋懷1 小时前
策略模式详解与应用
设计模式·策略模式
余辉zmh2 小时前
【优选算法篇】:分而治之--揭秘分治算法的魅力与实战应用
c++·算法
Lenyiin2 小时前
第424场周赛:使数组元素等于零、零数组变换 Ⅰ、零数组变换 Ⅱ、最小化相邻元素的最大差值
c++·算法·leetcode·周赛·lenyiin
北顾南栀倾寒2 小时前
[Qt]常用控件介绍-输入类控件-QLineEdit、QTextEdit、QComboBox控件
开发语言·c++·qt
0xCC说逆向2 小时前
Windows图形界面(GUI)-QT-C/C++ - QT信号与槽机制详解
java·c语言·开发语言·c++·windows·qt·mfc
奥特曼狂扁小怪兽2 小时前
C++ QT 自绘表盘
开发语言·c++·qt
汤姆和杰瑞在瑞士吃糯米粑粑3 小时前
【C++学习篇】红黑树 从入门到进阶
数据结构·c++·算法
Xiezequan4 小时前
c++ 手写queue循环队列
开发语言·c++