QT 事件驱动架构

很多大型系统(工业软件、机器人系统、自动驾驶、复杂 Qt 应用)在规模变大以后,都会逐渐引入 事件驱动架构(Event Bus / Event Driven Architecture)。

原因很简单:

当系统模块越来越多时,模块之间的调用关系会爆炸式增长,最终变得无法维护。

我用一个逐步演化的真实思维过程来解释。


一、最初阶段:直接调用(最直观)

系统刚开始只有几个模块:

  • UI
  • MotorController
  • CameraController

调用关系很简单:

复制代码
UI → MotorController
UI → CameraController

代码类似:

cpp 复制代码
void MainWindow::onStartClicked()
{
    motorController.start();
    cameraController.capture();
}

问题不大。


二、系统变大:调用关系开始爆炸

后来系统增加很多模块:

  • MotorController
  • CameraController
  • LightController
  • NetworkController
  • DataLogger
  • AlarmSystem
  • UI

此时如果还是直接调用,会变成:

复制代码
UI → MotorController
UI → CameraController
UI → LightController

MotorController → Logger
MotorController → Alarm

CameraController → Logger
CameraController → Network

Network → Controller

模块之间的关系变成一个 蜘蛛网结构:

复制代码
 A → B
 A → C
 B → D
 C → D
 D → E
 E → B

这叫:

强耦合系统

问题:

1️⃣ 修改一个模块可能影响很多模块

2️⃣ 新增功能需要改很多代码

3️⃣ 很难理解系统结构


三、真实案例:增加一个"报警系统"

假设系统需要增加一个新模块:

复制代码
AlarmSystem

需求:

  • 电机过载报警
  • 温度过高报警
  • 网络断开报警

如果是直接调用:

MotorController 要加:

cpp 复制代码
if(overload)
    alarm.raise("motor overload");

CameraController:

cpp 复制代码
if(cameraError)
    alarm.raise("camera error");

NetworkController:

cpp 复制代码
if(disconnect)
    alarm.raise("network error");

问题:

❌ 每个模块都要修改

❌ 未来新增模块还要继续改

这就是 耦合地狱。


四、工程师的思考:能不能让模块不互相认识?

工程师开始思考:

如果模块之间不直接调用,而是发布消息,会不会更好?

于是出现:

事件驱动架构


五、事件驱动架构的核心思想

模块之间不直接调用。

而是:

复制代码
发布事件

和

复制代码
订阅事件

通过一个 EventBus(事件总线) 连接。

结构变成:

复制代码
Module A → EventBus → Module B

模块之间 互相不知道对方存在。


六、例子:电机完成运动

传统调用:

复制代码
MotorController → CameraController

代码:

cpp 复制代码
motorController.moveDone();

cameraController.capture();

问题:

MotorController 必须知道 CameraController。


事件驱动:

复制代码
MotorController → EventBus
CameraController ← EventBus

代码:

发布事件:

cpp 复制代码
eventBus.publish("MotorMoveDone");

订阅事件:

cpp 复制代码
eventBus.subscribe("MotorMoveDone",
    [](){
        camera.capture();
    });

MotorController 不知道 CameraController。


七、增加新功能时的变化

假设我们新增:

复制代码
Logger

记录电机完成事件。

传统方式:

需要修改:

复制代码
MotorController
CameraController

事件方式:

只需要:

复制代码
Logger 订阅事件

代码:

cpp 复制代码
eventBus.subscribe("MotorMoveDone",
    [](){
        logger.log("motor finished");
    });

原代码 完全不需要改。


八、再举一个真实设备流程

自动检测设备流程:

复制代码
移动平台
→ 拍照
→ 图像检测
→ 上传结果

传统调用:

复制代码
MotionController
   ↓
CameraController
   ↓
InspectionController
   ↓
NetworkController

代码:

cpp 复制代码
motion.move();

camera.capture();

auto result = inspect.detect();

network.send(result);

模块互相依赖。


事件驱动:

复制代码
MotionController
   ↓
Event: MoveDone

CameraController
   ↓
Event: ImageCaptured

InspectionController
   ↓
Event: InspectionDone

结构:

复制代码
MotionController
      ↓
   EventBus
      ↓
CameraController
      ↓
   EventBus
      ↓
InspectionController

九、系统结构变化

没有 EventBus:

复制代码
A → B → C → D

有 EventBus:

复制代码
A → EventBus
B → EventBus
C → EventBus
D → EventBus

模块只依赖:

复制代码
EventBus

系统耦合大幅下降。


十、再举一个复杂例子(工业软件)

事件:

复制代码
TemperatureHigh

订阅者可能有:

复制代码
AlarmSystem
Logger
UI
CoolingController

发布者:

复制代码
SensorController

代码:

发布:

cpp 复制代码
eventBus.publish("TemperatureHigh");

订阅:

cpp 复制代码
eventBus.subscribe("TemperatureHigh",
    [](){ alarm.trigger(); });

eventBus.subscribe("TemperatureHigh",
    [](){ logger.log(); });

eventBus.subscribe("TemperatureHigh",
    [](){ ui.showWarning(); });

新增功能只需要:

复制代码
新增订阅者

十一、事件驱动带来的巨大好处

1 模块解耦

模块互相不认识。


2 可扩展

新增功能:

复制代码
新增订阅者

不用修改旧代码。


3 更符合现实世界

现实世界就是事件驱动:

复制代码
门打开 → 灯亮
门打开 → 摄像头启动
门打开 → 报警系统记录

4 易于并发

事件可以:

复制代码
异步处理
多线程处理

十二、Qt 为什么非常适合事件架构

Qt 本身就是 事件驱动框架。

例如:

复制代码
Signal → Slot

本质就是:

复制代码
Event → Listener

例子:

cpp 复制代码
connect(button,
        &QPushButton::clicked,
        this,
        &MainWindow::onClicked);

这其实就是一个小型 EventBus。


十三、大型系统为什么几乎都用事件架构

因为系统规模一大,就会出现:

复制代码
模块数量 ↑
调用关系 ↑↑
复杂度 ↑↑↑

EventBus可以把:

复制代码
N² 的调用关系

变成:

复制代码
N 的关系

这是复杂度降低的关键。


十四、一句话理解 EventBus

普通架构:

复制代码
模块直接打电话

事件架构:

复制代码
模块在广播电台发布消息
需要的人自己收听

相关推荐
天空属于哈夫克33 天前
企业微信二次开发:精准实现关键词自动回复
架构·企业微信
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
伞伞悦读3 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
晨米酱3 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
这个DBA有点耶3 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
C语言小火车3 天前
C/C++ 为什么需要编译器?
开发语言·c++
霍霍的袁3 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
moMo3 天前
从固定流程到问题路由:让 LangGraph RAG 按需检索
架构
孙启超3 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust