Qt的前端和后端过于耦合(0/7)

最近在写一个软件,这个软件稍微复杂一些,界面大概需要十几个,后端也是要开多线程读各种传感器数据。然后鼠鼠我呀就发现一个致命的问题,那就是前端要求的控件太多了,点一下就需要通知后端,即调用后端的函数,这是非常不友好的。因为耦合程度太高了,交互起来过于混乱严重影响开发进度。如果是一个人设计的可能稍微好一些(一个按钮实现一个函数呗),但是如果是团队分工的话就会很麻烦。后面问了大佬,大佬给我提供了一个思路,然后我会又去问了GPT。把相关的方法也写进来了。准备写个小合集,现在这里占个坑,后面在慢慢补齐。

大佬最后还给了一个建议:

要解耦,就不要想到什么功能立马实现地态度创建文件写实现,而是需要抱着写库的思路去写功能,把库(模块)写的差不多了再利用界面去调用接口


目录

[✅ 1. 信号与槽机制(Signals & Slots) ✅【小工程推荐】](#✅ 1. 信号与槽机制(Signals & Slots) ✅【小工程推荐】)

[✔ 特点:](#✔ 特点:)

[✔ 示例:](#✔ 示例:)

[✅ 2. 事件总线 / 消息中心(Event Bus / Message Center) ✅【适合全局广播】](#✅ 2. 事件总线 / 消息中心(Event Bus / Message Center) ✅【适合全局广播】)

[✔ 特点:](#✔ 特点:)

[✔ 示例实现:](#✔ 示例实现:)

[✅ 3. 观察者模式(Observer Pattern) 🧩【设计模式基础】](#✅ 3. 观察者模式(Observer Pattern) 🧩【设计模式基础】)

[✔ 特点:](#✔ 特点:)

[✅ 4. 发布-订阅模式(Pub-Sub Pattern) 🗞️【带中介的观察者模式】](#✅ 4. 发布-订阅模式(Pub-Sub Pattern) 🗞️【带中介的观察者模式】)

[✔ 特点:](#✔ 特点:)

[✅ 5. 自定义 QEvent + 事件投递机制(高级/底层)](#✅ 5. 自定义 QEvent + 事件投递机制(高级/底层))

[✔ 特点:](#✔ 特点:)

[✅ 6. MVC/MVVM 架构分层](#✅ 6. MVC/MVVM 架构分层)

[✔ 特点:](#✔ 特点:)

[✅ 7. 前后端分离架构(Frontend-Backend Separation)](#✅ 7. 前后端分离架构(Frontend-Backend Separation))

[✔ 模型](#✔ 模型)

[✔ 可选实现方式(C++ 服务端):](#✔ 可选实现方式(C++ 服务端):)

[✅ 总结对比表:](#✅ 总结对比表:)

[✅ Qt 中前后端通信与解耦方式对比(含跨进程/语言)](#✅ Qt 中前后端通信与解耦方式对比(含跨进程/语言))

[✅ 各方法适用范围速览:](#✅ 各方法适用范围速览:)

[✅ 推荐使用建议:](#✅ 推荐使用建议:)

[✅ Qt 多线程通信方法对比表](#✅ Qt 多线程通信方法对比表)


这里是邪恶的分界线


✅ 1. 信号与槽机制(Signals & Slots) ✅【小工程推荐】

✔ 特点:

  • Qt 原生支持

  • 松耦合、线程安全(带 QueuedConnection

  • 谁关心谁连接,不需要直接引用对象

✔ 示例:

cpp 复制代码
connect(controller, &Controller::dataUpdated, ui, &MainWindow::updateUI);

**优点:**前端 UI 和后端逻辑彼此独立,只通过信号/槽通信。

缺点也很明显,一次调用就需要写对应的信号函数和槽函数。UI界面如果功能要求很多的情况下会与其他的模块过于耦合。甚至改了一个点,代码就立即崩溃。

✔ 拓展:配合定时器实现定时巡查:

cpp 复制代码
    connect(mTimer, &QTimer::timeout, this, &类::onTimerTimeout);

✅ 2. 事件总线 / 消息中心(Event Bus / Message Center) ✅【适合全局广播】

✔ 特点:

  • 所有模块注册到一个全局消息中心

  • 事件发布者和订阅者互不依赖

  • 支持"一次广播,多方接收"

✔ 示例实现:

cpp 复制代码
// 发出事件
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)

cpp 复制代码
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) ✅(多进程) ✅(通过网络协议) ❌(通过响应处理) ⭐⭐⭐⭐ 前后端线程独立,由服务控制线程调度
相关推荐
www_stdio20 小时前
深入理解 Promise 与 JavaScript 原型链:从基础到实践
前端·javascript·promise
5***g29820 小时前
Windows安装Rust环境(详细教程)
开发语言·windows·rust
暮紫李20 小时前
项目中如何强制使用pnpm
前端
哈哈哈笑什么20 小时前
如何防止恶意伪造前端唯一请求id
前端·后端
XL's妃妃20 小时前
Java 基准测试工具 JMH 详细介绍
java·开发语言·测试工具
kevinzzzzzz20 小时前
基于模块联邦打通多系统的探索
前端·javascript
小胖霞20 小时前
彻底搞懂 JWT 登录认证与路由守卫(五)
前端·vue.js·node.js
用户938169125536020 小时前
VUE3项目--组件递归调用自身
前端
昔人'20 小时前
CSS content-visibility
前端·css