模块化设计基础:模块划分原则、接口设计规范、高内聚低耦合实战、模块间通信机制

好,咱们进入第二章。上一章聊了为什么要模块化,这一章直接上干货——怎么分模块、怎么定接口、怎么让模块之间不打架。

我见过太多项目,一开始图省事,把所有功能塞进一个 main.c。结果呢?三个月后,改一个定时器参数,莫名其妙把 SPI 通信搞崩了。这种痛,经历过一次就够了。

模块划分原则:别拍脑袋,要有章法

模块划分不是拍脑袋。我个人习惯,拿到需求先画一张「功能依赖图」。把每个独立的功能块圈出来,看看谁依赖谁。

核心原则就三条:
  • 单一职责——一个模块只做一件事,做好它
  • 接口最小化——暴露给外部的 API 越少越好
  • 依赖单向——模块之间不要形成循环依赖

举个例子。一个温控系统,我习惯拆成:温度采集模块、PID 计算模块、加热控制模块、用户界面模块。每个模块各司其职,谁也不越界。

我的经验: 模块粒度控制在 3~8 个函数为宜。太细了管理成本高,太粗了复用性差。我曾经把一个驱动拆成 20 个小文件,结果自己都找不着函数在哪。

接口设计规范:接口就是合同

接口设计,说白了就是签合同。合同写得模糊,后面全是扯皮。

我总结了一套接口设计 checklist,每次写接口前过一遍:

检查项 说明 反面案例
参数类型明确 用 typedef 定义专用类型,别裸用 int void setTemp(int t);
返回值统一 统一用 int 返回错误码,0 成功,负值错误 有的返回指针,有的返回 bool
命名规范 模块前缀 + 动作 + 对象 temp_set_target() 优于 set_temperature()
头文件自包含 每个 .h 能独立编译,不依赖前置包含 忘了 #include 就编译不过
// 好的接口示例
typedef enum {
    TEMP_OK = 0,
    TEMP_ERR_SENSOR = -1,
    TEMP_ERR_RANGE  = -2
} temp_err_t;

temp_err_t temp_set_target(int16_t temp_celsius);
temp_err_t temp_get_current(int16_t *out_temp);
避坑指南: 我曾经在接口里直接传结构体指针,结果模块内部改了结构体布局,外部全部编译失败。后来我强制用不透明指针 + 访问函数,接口稳定多了。

高内聚低耦合实战:别让模块互相「串门」

高内聚,就是模块内部的东西自己消化。低耦合,就是模块之间只通过接口说话,别直接访问对方的全局变量。

我常用的手法:

  • 全局变量私有化——所有全局变量加 static,只通过 getter/setter 暴露
  • 回调函数解耦——A 模块需要通知 B 模块时,用注册回调的方式,而不是直接调用
  • 状态机封装——模块内部状态对外不可见,外部只发事件
// 低耦合示例:通过回调解耦
typedef void (*temp_alert_cb_t)(int16_t temp);

static temp_alert_cb_t alert_cb = NULL;

void temp_register_alert_cb(temp_alert_cb_t cb) {
    alert_cb = cb;
}

static void temp_check_alert(void) {
    if (alert_cb && current_temp > TEMP_ALERT_THRESHOLD) {
        alert_cb(current_temp);
    }
}
实战技巧: 我习惯在模块头文件里只放接口声明,所有实现细节藏进 .c 文件。头文件里不要出现 #define 内部常量,更不要暴露内部结构体。这样别人看你的头文件,一眼就知道这个模块能干什么。

模块间通信机制:选对路子,事半功倍

模块之间总要通信。选什么机制,取决于场景。

通信方式 适用场景 优点 缺点
直接函数调用 同步、紧耦合、性能敏感 简单、零延迟 耦合度高
回调函数 事件驱动、异步通知 解耦好、灵活 回调地狱、调试困难
消息队列 多任务、异步、缓冲 解耦彻底、可缓冲 额外内存、延迟
共享变量 + 互斥 实时性要求高、数据量小 速度快 容易出竞态
全局事件标志 状态同步、简单通知 轻量、无数据拷贝 只能传标志位

我个人偏好:能用回调就别用全局变量,能用消息队列就别用共享内存。但也不是绝对的——在中断服务函数里,我通常只用标志位或消息队列,绝不在中断里做复杂调用。

血的教训: 我曾经在中断里直接调用另一个模块的函数,那个函数里有个互斥锁,结果死锁了。从那以后,我规定中断里只能发消息或置标志,所有处理挪到任务级。

模块化设计知识体系

下面这张图,是我做模块化设计时脑子里始终绷着的一根弦。它把模块划分、接口设计、高内聚低耦合、通信机制串在了一起。

模块化设计知识体系 模块化设计核心知识体系 模块划分原则 接口设计规范 高内聚低耦合 模块间通信机制 单一职责 接口最小化 依赖单向 参数类型明确 返回值统一 命名规范 头文件自包含 全局变量私有化 回调函数解耦 状态机封装 直接函数调用 回调函数 消息队列 共享变量+互斥 全局事件标志 核心思想 模块内部高内聚,模块之间低耦合,接口就是合同,通信选对路子