最近在写一个软件,这个软件稍微复杂一些,界面大概需要十几个,后端也是要开多线程读各种传感器数据。然后鼠鼠我呀就发现一个致命的问题,那就是前端要求的控件太多了,点一下就需要通知后端,即调用后端的函数,这是非常不友好的。因为耦合程度太高了,交互起来过于混乱严重影响开发进度。如果是一个人设计的可能稍微好一些(一个按钮实现一个函数呗),但是如果是团队分工的话就会很麻烦。后面问了大佬,大佬给我提供了一个思路,然后我会又去问了GPT。把相关的方法也写进来了。准备写个小合集,现在这里占个坑,后面在慢慢补齐。
大佬最后还给了一个建议:
要解耦,就不要想到什么功能立马实现地态度创建文件写实现,而是需要抱着写库的思路去写功能,把库(模块)写的差不多了再利用界面去调用接口
目录
✅ 1. 信号与槽机制(Signals & Slots) ✅【小工程推荐】
✅ 2. 事件总线 / 消息中心(Event Bus / Message Center) ✅【适合全局广播】
✅ 3. 观察者模式(Observer Pattern) 🧩【设计模式基础】
✅ 4. 发布-订阅模式(Pub-Sub Pattern) 🗞️【带中介的观察者模式】
✅ 5. 自定义 QEvent + 事件投递机制(高级/底层)
✅ 7. 前后端分离架构(Frontend-Backend Separation)
这里是邪恶的分界线
✅ 1. 信号与槽机制(Signals & Slots) ✅【小工程推荐】
✔ 特点:
Qt 原生支持
松耦合、线程安全(带
QueuedConnection
)谁关心谁连接,不需要直接引用对象
✔ 示例:
connect(controller, &Controller::dataUpdated, ui, &MainWindow::updateUI);
优点:前端 UI 和后端逻辑彼此独立,只通过信号/槽通信。
缺点也很明显,一次调用就需要写对应的信号函数和槽函数。UI界面如果功能要求很多的情况下会与其他的模块过于耦合。甚至改了一个点,代码就立即崩溃。
✔ 拓展:配合定时器实现定时巡查:
connect(mTimer, &QTimer::timeout, this, &类::onTimerTimeout);
✅ 2. 事件总线 / 消息中心(Event Bus / Message Center) ✅【适合全局广播】
✔ 特点:
所有模块注册到一个全局消息中心
事件发布者和订阅者互不依赖
支持“一次广播,多方接收”
✔ 示例实现:
// 发出事件
MessageCenter::instance().postMessage({ MessageType::JoystickAngleChanged, QVariant::fromValue(angle) });
// 监听事件
connect(&MessageCenter::instance(), &MessageCenter::messagePosted, this, [](const Message& msg) {
if (msg.type == MessageType::JoystickAngleChanged) {
float angle = msg.data.toFloat();
// 处理逻辑
}
});
✅ 3. 观察者模式(Observer Pattern) 🧩【设计模式基础】
✔ 特点:
手动实现:主题维护一组观察者列表
经典设计模式思想
不依赖 Qt,可用于非 QObject 类
Qt 的信号槽就是观察者模式的升级版
✅ 4. 发布-订阅模式(Pub-Sub Pattern) 🗞️【带中介的观察者模式】
✔ 特点:
和 Event Bus 类似,但更偏架构层
可用于模块化插件系统或多线程模块通信
可选中介:如 Qt 中心类、第三方消息库(如
eventpp
)
✅ 5. 自定义 QEvent + 事件投递机制(高级/底层)
✔ 特点:
适合底层系统级事件、跨线程通信
使用
QCoreApplication::postEvent()
发消息接收类需重写
QObject::event(QEvent* e)
QCoreApplication::postEvent(targetObject, new MyCustomEvent());
✅ 6. MVC/MVVM 架构分层
✔ 特点:
把逻辑层(Model/ViewModel)和界面层(View)彻底分离
使用信号/槽或绑定桥接
更适合大型项目
✅ 7. 前后端分离架构(Frontend-Backend Separation)
✔ 模型
客户端-服务器通信模型 + RESTful API 或 WebSocket 通信协议
C++ 后端作为服务,JS 前端通过 HTTPS 调用
后端 C++:实现逻辑处理、设备管理、数据计算,暴露 API(通过 REST 或 WebSocket)
前端 JS(如 Vue/React):调用后端接口、获取数据、展示 UI
通信方式:通过 HTTP(S) 请求(GET/POST/PUT/DELETE)广义的发布-订阅模式(或请求-响应模式)
通信例子(REST):
POST https://localhost:8000/api/update-angle
Content-Type: application/json
{
"angleX": 10.5,
"angleY": -2.1
}
✔ 可选实现方式(C++ 服务端):
技术 | 用途 |
---|---|
Cpp-REST SDK(Casablanca) | 微软支持的 REST 服务框架 |
Crow / Drogon / Pistache | 高性能 C++ Web 框架 |
gRPC + Protobuf | 更高效的 RPC 通信,非 HTTP |
Boost.Beast / ASIO | 低层 HTTP/WebSocket 支持 |
✅ 总结对比表:
✅ Qt 中前后端通信与解耦方式对比(含跨进程/语言)
方法 | 解耦性 | 使用难度 | 推荐场景 |
---|---|---|---|
信号与槽 | ⭐⭐⭐⭐ | ⭐⭐ | 通用通信,Qt 内部模块、UI ↔ 逻辑 |
事件总线(MessageCenter) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 全局通知、广播事件,解耦多个模块 |
观察者模式 | ⭐⭐⭐ | ⭐⭐ | 基础设计模式,适合无 Qt 场景 |
发布-订阅模式(带中介) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 插件系统、热插拔模块、多生产者消费者场景 |
QEvent 自定义 | ⭐⭐⭐ | ⭐⭐⭐⭐ | 底层事件处理、跨线程通信、自定义事件类型 |
MVC / MVVM 架构 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 中大型应用的分层架构设计,逻辑与表现分离 |
前后端分离(C++ + JS + HTTPS) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 跨语言/跨平台开发,Web UI 与本地后端通信 |
✅ 各方法适用范围速览:
方法 | 是否跨模块 | 是否跨语言 | 是否适合大型项目 | 是否线程安全 |
---|---|---|---|---|
信号与槽 | ✅ | ❌ | ✅(中小) | ✅(带 QueuedConnection ) |
事件总线 | ✅ | ❌ | ✅ | ✅(需注意线程) |
观察者模式 | ✅ | ❌ | ❌(基础) | ❌(需手动实现) |
发布-订阅 | ✅ | ❌(默认) | ✅ | ✅(实现复杂) |
QEvent 自定义 | ✅ | ❌ | ✅(系统级) | ✅ |
MVC/MVVM | ✅ | ❌(默认) | ✅✅ | ✅ |
前后端分离(HTTPS) | ✅✅ | ✅✅ | ✅✅✅ | ✅(通过 HTTP 协议) |
✅ 推荐使用建议:
🔧 轻量内部通信 → 用 Qt 自带的 信号与槽
📢 多个模块响应同一事件 → 用 事件总线 / 发布-订阅
🔋 需要插件式或热插拔功能 → 推荐 发布-订阅模式
⚙️ 跨线程通信 → 使用 QEvent 自定义 + postEvent
🧩 清晰结构、大型项目 → 使用 MVC/MVVM 架构
🌐 前后端用不同语言(如 JS + C++) → 使用 前后端分离 + HTTPS 或 WebSocket
✅ Qt 多线程通信方法对比表
在 多线程环境下,模块通信和解耦机制就必须考虑以下几个关键因素:
✅ 线程安全性(Thread Safety)
🔁 事件能否跨线程分发
🚧 使用复杂度 / 调试难度
🧵 是否自动切换线程上下文(如 UI 线程)
方法 | 跨线程能力 | 线程安全性 | 自动线程切换 | 使用难度 | 推荐场景(多线程) |
---|---|---|---|---|---|
信号与槽(QueuedConnection) | ✅ | ✅ | ✅(切 UI 线程) | ⭐⭐ | 后台线程通知 UI,常用 |
事件总线(MessageCenter) | ⚠️(需额外处理) | ❌(默认) / ✅(加锁) | ❌ | ⭐⭐⭐ | 多模块通信,需加锁或用 queued signal |
观察者模式 | ⚠️ | ❌ | ❌ | ⭐⭐ | 不推荐直接用于多线程 |
发布-订阅模式(线程安全实现) | ✅ | ✅(需封装) | ❌(或自处理) | ⭐⭐⭐⭐ | 多线程模块解耦(如后台计算、日志分发) |
QEvent 自定义 + postEvent() | ✅✅ | ✅ | ❌(需手动处理) | ⭐⭐⭐⭐ | 跨线程消息队列,精准控制投递目标 |
MVC / MVVM 架构 | ⚠️(依赖实现) | ⚠️(需要配合线程机制) | ❌ | ⭐⭐⭐⭐ | 与线程模型组合使用,如后台模型 + UI 表现 |
前后端分离(HTTPS/WebSocket) | ✅(多进程) | ✅(通过网络协议) | ❌(通过响应处理) | ⭐⭐⭐⭐ | 前后端线程独立,由服务控制线程调度 |