第三章 架构设计原则:模块化设计、分层架构、高内聚低耦合
好,咱们进入正题。这一章聊的是架构设计的核心原则。说白了,就是怎么把一个大系统拆得明明白白,让每个人各司其职,出了问题也能快速定位。
我做了这么多年嵌入式中间件,见过太多「一锅粥」式的代码。一个文件几千行,全局变量满天飞,改一个功能要动十个模块。嗯,这种项目,后期维护成本高得吓人。所以今天咱们把这三个原则掰开揉碎了讲清楚。
3.1 模块化设计:拆,是门艺术
模块化设计,就是把一个复杂系统拆成若干个独立的功能单元。每个单元负责一件事,做好它。
为什么要拆?你想想看,一个网关中间件,要处理协议转换、数据缓存、日志记录、设备管理……如果全揉在一起,一个人根本hold不住。拆开之后,每个人负责一个模块,开发效率翻倍。
我个人习惯,模块划分遵循两个原则:
- 功能单一:一个模块只做一件事。比如「协议解析模块」只管解析,别管数据存哪。
- 接口清晰:模块之间通过定义好的接口通信,别偷偷摸摸访问全局变量。
举个例子,一个简单的日志模块:
/* log_module.h */
#ifndef LOG_MODULE_H
#define LOG_MODULE_H
typedef enum {
LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO,
LOG_LEVEL_WARN,
LOG_LEVEL_ERROR
} log_level_t;
void log_init(const char *filename);
void log_write(log_level_t level, const char *fmt, ...);
void log_close(void);
#endif /* LOG_MODULE_H */
你看,这个模块只暴露了三个函数:初始化、写日志、关闭。内部怎么实现?用文件还是串口?那是模块自己的事。调用者不需要知道。
3.2 分层架构:三层结构,各司其职
分层架构,就是把系统按职责分成几个「层」。每一层只跟相邻层打交道。咱们的嵌入式网关中间件,我建议分三层:
| 层次 | 职责 | 典型内容 |
|---|---|---|
| 硬件抽象层(HAL) | 屏蔽硬件差异 | GPIO、UART、SPI、I2C 驱动封装 |
| 核心服务层 | 提供通用服务 | 协议栈、数据缓存、任务调度、日志 |
| 应用接口层 | 暴露给上层应用 | API 接口、回调注册、配置管理 |
硬件抽象层,说白了就是给硬件穿件「外套」。不同厂家的MCU,GPIO操作可能完全不同。但通过HAL,上层看到的都是统一的接口:hal_gpio_set()、hal_uart_send()。换芯片?只改HAL层就行。
核心服务层,这是中间件的「大脑」。协议转换、数据缓存、任务调度都在这里。它不关心底层是哪个芯片,也不关心上层是什么应用。它只做好自己的事。
应用接口层,是给应用开发者看的。他们不需要知道底层怎么跑,只需要调用几个API就能完成功能。比如:
/* 应用接口层示例 */
int gateway_send_data(uint8_t *data, uint32_t len);
int gateway_register_callback(gateway_event_t event, void (*cb)(void *));
3.3 高内聚低耦合:模块的「内功」与「外交」
这两个词,你肯定听过。但真正理解的人不多。
高内聚,就是一个模块内部的东西,应该紧密相关。比如一个「数据缓存模块」,里面所有函数都应该跟缓存操作有关。别把「计算校验和」也塞进去,那是另一个模块的事。
低耦合,就是模块之间的依赖要尽可能少。A模块改了,B模块最好不用动。
怎么做到?我分享几个实战技巧:
- 用接口,别用全局变量:模块之间通过函数调用或消息队列通信,别共享全局变量。全局变量是耦合的万恶之源。
- 定义好契约:接口的参数、返回值、行为,要明确写在头文件里。调用者只依赖这个契约,不依赖实现细节。
- 依赖倒置:高层模块不依赖低层模块,两者都依赖抽象接口。这个有点深,后面章节会细讲。
举个例子,一个低耦合的定时器模块设计:
/* timer_module.h */
typedef void (*timer_callback_t)(void *arg);
int timer_create(uint32_t interval_ms, timer_callback_t cb, void *arg);
int timer_delete(int timer_id);
你看,这个模块只暴露了创建和删除定时器的接口。具体用硬件定时器还是软件定时器?那是模块内部的事。调用者只需要提供回调函数和参数就行。
核心要点:
- 模块化:拆成独立单元,每个单元只做一件事
- 分层:HAL、核心服务、应用接口,三层各司其职
- 高内聚:模块内部紧密相关
- 低耦合:模块之间依赖最少
嗯,这三个原则,说起来简单,做起来需要经验积累。我刚开始做架构时,也经常把模块拆得太碎,或者层与层之间界限模糊。后来慢慢摸索,才找到平衡点。
记住一句话:好的架构,是改出来的。别指望一次设计就完美。先搭个框架,跑起来,然后根据实际需求不断调整。这才是实战中的常态。
下一章,咱们聊聊具体怎么搭这个三层架构的代码骨架。到时候我会拿一个真实的网关项目做例子,手把手带你走一遍。