观察者模式——C++
2026/9/5 3:50:53 网站建设 项目流程

观察者模式(Observer Pattern)

观察者模式是一种行为型设计模式。

它解决的问题很简单:

一个对象的状态发生变化时,需要自动通知多个其他对象。

例如:

Qt 的 signal / slot
微信公众号:发布文章 → 多个用户收到通知
股票:股票价格变化 → 多个界面自动刷新
温度传感器:温度变化 → 温度显示、报警器、记录器同时更新
MVC:Model 数据变化 → View 自动刷新
一、先理解一个生活中的例子

假设有一个气象站:

气象站 │ 温度发生变化 │ ┌─────┼─────┐ ↓ ↓ ↓ 温度显示 手机App 报警器

气象站并不需要知道每个设备具体如何处理。

它只需要:

通知所有观察者

每个观察者自己决定收到通知后做什么。

这就是观察者模式的核心思想。

二、观察者模式的结构

主要有两个角色:

1. Subject(主题/被观察者)

负责:

保存观察者
添加观察者
删除观察者
状态发生变化时通知观察者
2. Observer(观察者)

负责:

接收通知
根据通知执行自己的操作

结构:

Subject │ notify()│ ┌────────┼────────┐ ↓ ↓ ↓ ObserverA ObserverB ObserverC

三、最简单的 C++ 实现

我们模拟一个温度传感器。

Observer.h#ifndef OBSERVER_H#define OBSERVER_Hclass Observer{public: virtual ~Observer(){}virtual void update(float temperature)=0;};#endif

这里定义观察者接口。

所有观察者都必须实现:

update()
Subject

#ifndefSUBJECT_H#defineSUBJECT_H#include<vector>#include"observer.h"classSubject{public:virtual~Subject(){}voidattach(Observer*observer){m_observers.push_back(observer);}voiddetach(Observer*observer){for(autoit=m_observers.begin();it!=m_observers.end();++it){if(*it==observer){m_observers.erase(it);break;}}}protected:voidnotify(floattemperature){for(Observer*observer:m_observers){observer->update(temperature);}}private:std::vector<Observer*>m_observers;};#endif

四、实现温度传感器

#ifndefTEMPERATURESENSOR_H#defineTEMPERATURESENSOR_H#include"subject.h"classTemperatureSensor:publicSubject{public:voidsetTemperature(floattemperature){m_temperature=temperature;// 温度发生变化notify(m_temperature);}floattemperature()const{returnm_temperature;}private:floatm_temperature=0;};#endif

重点就是:

m_temperature = temperature;
notify(m_temperature);

温度变化之后,自动通知所有观察者。

五、创建具体观察者
温度显示器

#include<iostream>#include"observer.h"classTemperatureDisplay:publicObserver{public:voidupdate(floattemperature)override{std::cout<<"温度显示器:当前温度 = "<<temperature<<" ℃"<<std::endl;}};

报警器

#include<iostream>#include"observer.h"classTemperatureAlarm:publicObserver{public:voidupdate(floattemperature)override{if(temperature>30){std::cout<<"报警器:温度过高!"<<std::endl;}}};

日志记录器

#include<iostream>#include"observer.h"classTemperatureLogger:publicObserver{public:voidupdate(floattemperature)override{std::cout<<"日志:记录温度 "<<temperature<<" ℃"<<std::endl;}};

六、测试

#include"temperaturesensor.h"intmain(){TemperatureSensor sensor;TemperatureDisplay display;TemperatureAlarm alarm;TemperatureLogger logger;sensor.attach(&display);sensor.attach(&alarm);sensor.attach(&logger);sensor.setTemperature(25);std::cout<<"----------------"<<std::endl;sensor.setTemperature(35);return0;}

运行:

温度显示器:当前温度 = 25 ℃
日志:记录温度 25 ℃

温度显示器:当前温度 = 35 ℃
报警器:温度过高!
日志:记录温度 35 ℃
七、这个模式最重要的地方

注意:

TemperatureSensor

完全不知道:

TemperatureDisplay
TemperatureAlarm
TemperatureLogger

它只知道:

Observer

也就是说:

TemperatureSensor │ │ 依赖抽象 ↓ Observer ↑ │ ┌─────┼────────┐ ↓ ↓ ↓ 显示器 报警器 日志

这就是观察者模式最核心的思想:

面向抽象,而不是面向具体观察者。

八、如果用 Qt,观察者模式就非常熟悉了

其实你平时写 Qt:

connect(button,
&QPushButton::clicked,
this,
&MainWindow::onClicked);

本质上就具有非常明显的观察者模式思想。

例如:

QPushButton │ │ clicked ↓ ┌───┼───────────────┐ ↓ ↓ ↓ 窗口 日志系统 其他对象

按钮是被观察者/事件发送者。

其他对象是观察者。

Qt 使用:

signal

表示事件通知:

signals:
void temperatureChanged(float temperature);

然后:

connect(sensor,
&TemperatureSensor::temperatureChanged,
display,
&TemperatureDisplay::update);

这样温度变化的时候:

emit temperatureChanged(temperature);

所有连接的对象都会收到通知。

九、Qt 中写一个观察者模式实例

例如温度传感器:

classTemperatureSensor:publicQObject{Q_OBJECTpublic:voidsetTemperature(floattemperature){if(qFuzzyCompare(m_temperature,temperature))return;m_temperature=temperature;emittemperatureChanged(m_temperature);}signals:voidtemperatureChanged(floattemperature);private:floatm_temperature=0;};

观察者:

classTemperatureDisplay:publicQObject{Q_OBJECTpublicslots:voidonTemperatureChanged(floattemperature){qDebug()<<"当前温度:"<<temperature;}};

连接:

TemperatureSensor sensor;TemperatureDisplay display;QObject::connect(&sensor,&TemperatureSensor::temperatureChanged,&display,&TemperatureDisplay::onTemperatureChanged);

然后:

sensor.setTemperature(25);

就会自动执行:

display.onTemperatureChanged(25);
十、观察者模式和发布-订阅的区别

这两个概念非常容易混。

观察者模式

通常是:

Subject │ ├──── Observer1 ├──── Observer2 └──── Observer3

Subject 直接持有 Observer。

例如:

std::vector<Observer *> m_observers;
发布-订阅

通常中间还有一个消息中心:

Publisher │ ↓ MessageBus │ ┌──┼────┐ ↓ ↓ ↓ Sub1 Sub2 Sub3

Publisher 不直接知道 Subscriber。

Qt 的 signal/slot、消息总线、事件总线等场景经常会出现这种思想。

十一、观察者模式的优点
① 解耦

比如:

TemperatureSensor

不需要知道:

TemperatureAlarm

所以报警器可以随时增加、删除。

② 支持一对多

一个对象变化:

Sensor │ ┌──────┼──────┐ ↓ ↓ ↓ 显示器 报警器 日志

可以通知很多对象。

③ 扩展方便

以后增加:

TemperatureCloudUploader

只需要:

class TemperatureCloudUploader : public Observer
{

};

然后:

sensor.attach(&cloudUploader);

原来的 Sensor 不需要修改。

这符合开闭原则。

十二、观察者模式的缺点
① 观察者太多

如果:

Subject
├── Observer1
├── Observer2
├── …
└── Observer1000

一次通知可能触发大量操作。

② 通知链可能复杂

比如:

A变化

通知B

B变化

通知C

C变化

通知A

甚至可能造成:

无限循环

所以实际项目中需要注意通知关系。

③ 生命周期问题

传统 C++ 实现:

std::vector<Observer*> m_observers;

如果 Observer 被释放了:

delete observer;

Subject 里面还保存着这个指针,就可能出现:

野指针

Qt 的信号槽在 QObject 生命周期管理方面就方便很多。

十三、什么时候适合使用?

看到下面这种需求,可以考虑观察者模式:

一个对象发生变化,需要自动让多个对象知道。

例如你现在做 Qt/C++ 项目,很常见:

配置发生变化 ↓ ┌────┼────────┐ ↓ ↓ ↓ UI 日志 设备控制

或者:

设备状态改变 ↓ ┌────┼─────────┐ ↓ ↓ ↓ 界面 数据记录 报警

或者:

图像处理参数改变 ↓ ┌─────┼─────────┐ ↓ ↓ ↓ 图像 曲线 参数显示 刷新 刷新 刷新

这种场景特别适合观察者模式。

一句话记忆:

观察者模式 = 一个对象发生变化,自动通知一群依赖它的对象。

而在 Qt 中,你可以把它直接对应成:

观察者模式

Subject → signals
Observer → slots
notify → emit
attach → connect

所以如果你正在学习设计模式并且主要用 Qt/C++,观察者模式是非常值得重点掌握的一个模式。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询