第3章 抽象工厂模式实现平台适配层:产品族约束、配置驱动、扩展点与风险
3.1 边界与分层
抽象工厂模式在 Framework 层中主要承担平台适配层的职责,其边界位于 Framework 核心逻辑与底层操作系统/硬件平台之间。该层负责将一组相关的平台抽象对象(产品族)统一创建,从而隔离上层代码对具体平台依赖。
| 层级 | 角色 | 边界描述 |
|---|---|---|
| Framework 核心 | 调用者 | 只依赖抽象产品接口,不感知具体平台实现 |
| 平台适配层 | 抽象工厂 + 具体工厂 | 封装平台差异,按配置创建产品族 |
| 底层系统/硬件 | 资源提供方 | 提供系统调用、驱动接口、HAL 能力 |
3.2 组件职责
- 抽象工厂(AdaptorFactory):声明创建一组抽象产品的方法,例如
createThread()、createMutex()、createFileSystem()。 - 具体工厂(LinuxAdaptorFactory / ZephyrAdaptorFactory):实现每个抽象方法,返回对应平台的实际产品实例。
- 抽象产品(Thread / Mutex / FileSystem):定义平台无关的接口规范。
- 具体产品(LinuxThread / ZephyrMutex):封装平台特定的系统调用或 HAL 函数。
- 配置解析器:读取运行时配置或编译时宏,决定使用哪个具体工厂。
3.3 产品族约束
产品族约束是抽象工厂模式的核心前提——某一平台下,所有具体产品必须彼此兼容。例如 Linux 平台下线程、互斥量、文件系统实现应使用同一套系统调用集(pthread + glibc),不能混入 Zephyr 的 POSIX 子集实现。
// 平台适配层抽象工厂接口
class PlatformAdaptor {
public:
virtual ~PlatformAdaptor() = default;
virtual Thread* createThread(const char* name) = 0;
virtual Mutex* createMutex() = 0;
virtual FileSystem* createFileSystem() = 0;
};
// Linux 具体工厂:保证所有产品使用同一套系统调用族
class LinuxAdaptor : public PlatformAdaptor {
public:
Thread* createThread(const char* name) override { return new LinuxThread(name); }
Mutex* createMutex() override { return new PthreadMutex(); }
FileSystem* createFileSystem() override { return new LinuxFileSystem(); }
};
违反产品族约束会直接导致运行时二进制不兼容或链接错误。Framework 层设计时应将产品族约束作为编译期静态检查项。
3.4 配置驱动
具体工厂的选择策略分为编译时与运行时两种:
- 编译时配置:通过 CMake 变量或宏定义指定平台,例如
-DTARGET_PLATFORM=ZEPHYR,在#if中条件编译具体工厂。 - 运行时配置:通过 JSON/YAML 配置文件或环境变量动态加载工厂,适用于 FPGA/模拟器切换场景。
// 运行时配置示例(JSON)
{
"platform": "zephyr",
"thread_stack_size": 4096,
"use_static_mutex": false
}
3.5 数据流/控制流/信任链路
数据流:上层代码 → 抽象工厂 factory.createThread() → 具体工厂 LinuxAdaptor::createThread() → 具体产品 LinuxThread → 返回抽象接口指针给上层。
控制流:配置解析器 → 工厂选择器 → 调用具体工厂的构造方法 → 完成产品族初始化。
信任链路:Framework 核心信任抽象产品接口契约;平台适配层信任具体工厂返回的对象满足接口语义;具体产品信任底层系统调用正确实现。
控制流:配置解析器 → 工厂选择器 → 调用具体工厂的构造方法 → 完成产品族初始化。
信任链路:Framework 核心信任抽象产品接口契约;平台适配层信任具体工厂返回的对象满足接口语义;具体产品信任底层系统调用正确实现。
3.6 内联 SVG:抽象工厂平台适配层结构
3.7 选型权衡
| 方案 | 优点 | 缺点 |
|---|---|---|
| 抽象工厂模式 | 产品族统一约束,新增平台只需添加具体工厂类,符合开闭原则 | 产品族扩展需修改抽象工厂接口(违反开闭),多层继承增加代码量 |
| 工厂方法 + 模板特化 | 避免抽象工厂接口膨胀,编译期多态性能好 | 运行时动态切换困难,模板错误信息晦涩 |
| 配置+if-else链 | 实现简单,适合平台数量 ≤3 的场景 | 违反开闭原则,平台增加导致代码膨胀,难以维护 |
推荐场景:平台数 ≥3 且产品族稳定(如嵌入式 RTOS + Linux + 裸机)时优先使用抽象工厂模式;短期原型可用配置+if-else 快速验证。
3.8 风险点
风险 1:产品族约束泄露——具体工厂返回的对象可能不符合抽象接口约定,例如 Linux 下的 Mutex 实现依赖了线程优先级排序,而 Zephyr 的互斥量不支持。解决:增加集成测试用例覆盖每个产品的边界语义。
风险 2:配置错误导致工厂选择失败——运行时不存在的平台字符串会导致空指针或未定义行为。解决:提供工厂注册表(Registry)并启用静态断言检查。
风险 3:二进制体积膨胀——同时编译所有具体工厂可能增大 ROM 占用。解决:使用条件编译 + 链接时优化排除未用符号。
3.9 落地步骤
- 定义抽象产品接口(Thread、Mutex、FileSystem)并编写单元测试桩。
- 创建抽象工厂基类
PlatformAdaptor,声明纯虚创建方法。 - 为每个目标平台实现具体工厂类(LinuxAdaptor、ZephyrAdaptor)。
- 实现配置解析器(编译时或运行时),绑定工厂选择逻辑。
- 在 Framework 核心初始化阶段调用工厂获取产品族实例。
- 在 CI 中增加多平台编译、链接及功能集成测试。
3.10 验收标准
- 支持至少两种异构平台(如 Linux + Zephyr)的无缝切换,仅通过配置变更触发。
- 上层代码无需包含任何平台相关的
#ifdef或系统头文件。 - 若配置指定非法平台,编译期报错(静态配置)或返回 nullptr 且日志记录(动态配置)。
- 新增第三个平台时,无需修改任何已有抽象产品接口或 Framework 核心代码(仅需新增具体工厂类并注册)。
- 产品族内部各对象之间的互操作正确性通过集成测试验证(例如 Thread 创建后协程切换不与 Mutex 死锁)。