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

embedded/2025/1/19 4:01:17/

观察者模式 (Observer)

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


意图

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

使用场景

  1. 事件驱动系统

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

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

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

参与者角色

  1. 主题 (Subject)

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

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

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

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

示例代码

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

#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 方法,用于接收通知:
class Observer {
public:virtual ~Observer() = default;virtual void update(const std::string& message) = 0; // 接收通知
};
2. 具体观察者 (ConcreteObserver)
  • 实现了 Observer 接口,并通过 update 方法更新状态:
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 方法:
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)
  • 存储观察者列表,并在状态改变时通知观察者:
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 方法触发通知:
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. 分布式系统

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

总结

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


http://www.ppmy.cn/embedded/155132.html

相关文章

PyTorch DAY2: 搭建神经网络

如今&#xff0c;我们已经了解了 PyTorch 中张量及其运算&#xff0c;但这远远不够。本次实验将学会如何使用 PyTorch 方便地构建神经网络模型&#xff0c;以及 PyTorch 训练神经网络的步骤及方法。 知识点 PyTorch 构建神经网络Sequential 容器结构使用 GPU 加速训练模型保存…

JVM:ZGC详解(染色指针,内存管理,算法流程,分代ZGC)

1&#xff0c;ZGC&#xff08;JDK21之前&#xff09; ZGC 的核心是一个并发垃圾收集器&#xff0c;所有繁重的工作都在Java 线程继续执行的同时完成。这极大地降低了垃圾收集对应用程序响应时间的影响。 ZGC为了支持太字节&#xff08;TB&#xff09;级内存&#xff0c;设计了基…

Python从0到100(八十四):神经网络-卷积神经网络训练CIFAR-10数据集

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

CV与NLP经典大模型解读

一。llm与lora微调策略解读 (1)文本大模型 llama:meta开源语言模型(咱们能负担得起下游任务了)。 lora:绘你模型你也得能训练的动才行(咱们也能微调下游任务)。loradiffusion。 self-instruct:下游任务得规矩些&#xff0c;输入与输出都得有一个标准格式。 peft:将上面三个…

Python----Python高级(面向对象:封装、继承、多态,方法,属性,拷贝,组合,单例)

一、封装 隐藏对象的属性和实现细节&#xff0c;只对外提供必要的方法。相当于将“细节封装起来”&#xff0c;只对外暴露“相关调用方法”。 Python追求简洁的语法&#xff0c;没有严格的语法级别的“访问控制符”&#xff0c;更多的是依靠程序员自觉实现。 class BankAccoun…

yolo训练数据集样本的标签形状一致是什么意思

“标签形状一致”指的是每个样本的标签数据在维度和大小上必须是相同的。例如&#xff0c;在目标检测任务中&#xff0c;标签通常包含目标的位置信息&#xff08;例如&#xff0c;[class, x_center, y_center, width, height]&#xff09;&#xff0c;每个目标在图像中的标签应…

密码学——密码学基础、散列函数与数字签名

1.密码学概述 是信息安全的基础和核心&#xff0c;是防范各种安全威胁的重要手段&#xff0c;信息安全的许多相关知识都与密码学相关。 密码学发展 密码学是一门古老而又年轻的学科 &#xff0c;几千年以前就存在&#xff0c;至今仍在发展演进。地位非常重要甚至起决定性作用…

python实现批量视频提取音频

1、安装依赖库 首先需要安装依赖库moviepy pip install moviepy 2、找到对应目录 利用listdir列出目标文件夹以下文件&#xff0c;利用os.path.join进行路径拼接&#xff0c;os.path.splitext()[0]扣掉。MP4后缀&#xff0c;加入所需形式&#xff0c;&#xff08;这里用的是…