1. 背景与目标
在 Qt 桌面软件开发中,界面刷新、状态同步、定时更新等场景往往存在一对多通知关系。 本模块将项目中的观察者逻辑抽象为独立能力,目标是:
- 解耦"事件发布者"和"界面更新者"
- 提供可复用的注册/通知/解绑机制
- 支持通知前后钩子,便于扩展业务流程
- 支持互斥控件保护,适配寄存器同步类场景
2. 观察者模式在本模块中的落地
观察者模式核心思想是:
Subject维护观察者列表- 状态变化时
Subject主动通知所有观察者 Observer在回调中执行各自更新逻辑
本模块将这一过程封装为三个核心角色:
SubjectWidgetModule:通用发布者(注册/反注册/通知)ObserverWidgetModule:通用观察者基类(绑定/解绑/更新入口)SyncByRegSubjectModule:带互斥控件保护的发布者扩展
3. 模块结构
modules/observer_module/observer_module.hmodules/observer_module/observer_module.cppmodules/observer_module/example_usage.cpp
4. 核心接口说明
4.1 SubjectWidgetModule
主要职责:
- 维护观察者列表(线程安全)
- 分配唯一观察者 ID
- 执行通知流程
关键接口:
quint32 addObserver(QWidget *widget, ObserverCallback callback, void *context = nullptr)bool removeObserver(quint32 observerId)void clearObservers()void notify()
设计要点:
notify()内部先复制快照再遍历,避免回调中增删订阅导致遍历失效- 提供
onBeforeNotify()/onAfterNotify()钩子,支持模板方法扩展
4.2 ObserverWidgetModule
主要职责:
- 封装绑定和解绑生命周期
- 向业务子类暴露统一更新入口
onUpdate()
关键接口:
bool bind(SubjectWidgetModule *subject, QWidget *widget)void unbind()virtual void onUpdate(QWidget *widget) = 0
设计要点:
- 析构时自动
unbind(),降低资源泄漏和悬挂订阅风险 unbind()幂等,可重复调用
4.3 SyncByRegSubjectModule
主要职责:
- 在通知前后自动执行互斥控件控制
依赖接口:
IExclusiveWidgetController
行为:
- 通知前调用
disableWidgets() - 通知后调用
enableWidgets()
5. 快速使用示例
#include "modules/observer_module/observer_module.h"
using namespace observer_module;
class MyObserver : public ObserverWidgetModule {
protected:
void onUpdate(QWidget *widget) override
{
Q_UNUSED(widget);
// 在这里执行 UI 或模型更新
}
};
void demo(QWidget *target)
{
SubjectWidgetModule subject;
MyObserver observer;
observer.bind(&subject, target);
subject.notify();
observer.unbind();
}
6. 互斥控件场景示例
#include "modules/observer_module/observer_module.h"
using namespace observer_module;
class MyExclusiveController : public IExclusiveWidgetController {
public:
void disableWidgets() override
{
// 通知前禁用控件
}
void enableWidgets() override
{
// 通知后恢复控件
}
};
void demoSync(QWidget *target)
{
MyExclusiveController controller;
SyncByRegSubjectModule subject(&controller);
quint32 id = subject.addObserver(
target,
[](QWidget *widget, void *context) {
Q_UNUSED(context);
Q_UNUSED(widget);
// 执行寄存器读取并刷新界面
});
subject.notify();
subject.removeObserver(id);
}
7. 与原项目类映射关系
Subject_widget->SubjectWidgetModuleObserver_widget->ObserverWidgetModuleSubject_sync_ui_by_reg->SyncByRegSubjectModule
8. 工程集成方式
将以下文件加入 .pro:
SOURCES += \
modules/observer_module/observer_module.cpp
HEADERS += \
modules/observer_module/observer_module.h
如需复用现有 Exclusive_widget_mgr,可增加一个适配器:
class ExclusiveWidgetMgrAdapter : public observer_module::IExclusiveWidgetController {
public:
explicit ExclusiveWidgetMgrAdapter(Exclusive_widget_mgr *mgr) : mgr_(mgr) {}
void disableWidgets() override
{
if (mgr_) {
mgr_->disable_exclusive_widgets();
}
}
void enableWidgets() override
{
if (mgr_) {
mgr_->enable_exclusive_widgets();
}
}
private:
Exclusive_widget_mgr *mgr_ = nullptr;
};
9. 适用场景与收益
适用场景:
- 多个控件同步同一数据源
- 定时刷新 UI
- 一处状态变化触发多处联动更新
收益:
- 降低模块耦合度
- 提升可维护性和可测试性
- 统一通知流程,减少重复代码