嵌入式设计模式之适配器模式(1)
适配器模式的核心思想将一个类的接口转换成客户端期望的另一个接口使原本接口不兼容的类可以一起工作。嵌入式适配器模式解决的典型问题1. 新旧硬件接口兼容问题问题场景旧系统使用模拟传感器电压输出0-5V新系统使用数字传感器I2C/SPI接口但业务代码期望统一的读取接口传统做法的困境// 业务层需要处理两种完全不同接口 float read_sensor(SensorType type) { if (type ANALOG_SENSOR) { int adc_value read_adc(ADC_CHANNEL_1); // 模拟读取 return adc_value * 0.1; // 电压转温度 } else if (type DIGITAL_SENSOR) { uint8_t data[2]; i2c_read(SENSOR_ADDR, data, 2); // 数字读取 return (data[0] 8 | data[1]) * 0.0625; // 原始值转温度 } } // 问题业务层需要了解具体硬件细节耦合度高2. 不同厂家驱动接口统一问题场景厂家A的显示屏驱动lcd_draw_pixel(x, y, color)厂家B的显示屏驱动display_set_point(x, y, rgb)但图形库期望统一的绘制接口3. 通信协议转换问题场景设备内部使用UART通信字节流外部需要USB HID协议数据包格式需要实现协议转换适配适配器模式实现方案结构组成目标接口Target客户端期望的接口被适配者Adaptee需要被适配的现有接口适配器Adapter实现目标接口包装被适配者具体实现示例场景统一传感器读取接口1. 定义目标接口期望的通用传感器接口// target_interface.h - 目标接口 typedef struct { int (*init)(void); float (*read_value)(void); // 统一返回浮点数值 void (*deinit)(void); } SensorInterface;2. 被适配者 - 模拟传感器现有接口// analog_sensor.h - 被适配者原有接口 typedef struct { int (*adc_init)(uint8_t channel); int (*read_adc_value)(uint8_t channel); // 返回ADC原始值(0-4095) } AnalogSensor; // 模拟传感器操作 int analog_sensor_init(uint8_t channel) { return adc_channel_init(channel); } int analog_sensor_read(uint8_t channel) { return read_adc(channel); // 返回0-4095的原始值 }3. 被适配者 - 数字传感器现有接口// digital_sensor.h - 另一个被适配者 typedef struct { int (*i2c_init)(uint8_t dev_addr); int (*read_i2c_data)(uint8_t dev_addr, uint8_t *data, uint8_t len); } DigitalSensor; int digital_sensor_init(uint8_t addr) { return i2c_device_init(addr); } int digital_sensor_read(uint8_t addr, uint8_t *data, uint8_t len) { return i2c_read(addr, data, len); // 读取原始字节数据 }4. 适配器实现// sensor_adapter.c /* 模拟传感器适配器 */ static int analog_adapter_init(void) { return analog_sensor_init(ADC_CHANNEL_1); // 调用被适配者接口 } static float analog_adapter_read_value(void) { int raw_value analog_sensor_read(ADC_CHANNEL_1); // 适配逻辑ADC原始值转实际物理量 return (raw_value / 4095.0) * 5.0 * 100; // 假设转换为温度值 } static void analog_adapter_deinit(void) { adc_channel_deinit(ADC_CHANNEL_1); } // 模拟传感器适配器实例 const SensorInterface analog_sensor_adapter { analog_adapter_init, analog_adapter_read_value, analog_adapter_deinit }; /* 数字传感器适配器 */ static int digital_adapter_init(void) { return digital_sensor_init(0x48); // 传感器I2C地址 } static float digital_adapter_read_value(void) { uint8_t data[2]; digital_sensor_read(0x48, data, 2); // 适配逻辑原始数据转实际值 int raw_temp (data[0] 8) | data[1]; return raw_temp * 0.0625; // 12位精度温度传感器转换 } static void digital_adapter_deinit(void) { i2c_device_deinit(0x48); } // 数字传感器适配器实例 const SensorInterface digital_sensor_adapter { digital_adapter_init, digital_adapter_read_value, digital_adapter_deinit };5. 客户端使用业务层// application.c - 客户端代码 void read_all_sensors(void) { SensorInterface* sensors[] { analog_sensor_adapter, // 模拟温度传感器 digital_sensor_adapter, // 数字温度传感器 // 可以轻松添加更多传感器适配器 }; for (int i 0; i sizeof(sensors)/sizeof(sensors[0]); i) { sensors[i]-init(); float value sensors[i]-read_value(); // 统一接口调用 printf(Sensor%d: %.2f\n, i, value); sensors[i]-deinit(); } }适配器模式在嵌入式的优势1. 接口统一化解决痛点不同硬件、不同厂家的驱动接口差异效果业务层代码与具体硬件解耦2. 代码复用解决痛点旧硬件驱动无法直接在新系统中使用效果通过适配器重用现有代码减少重写成本3. 简化系统集成解决痛点集成第三方库或模块时接口不匹配效果快速适配外部组件加速开发进度4. 提高可测试性解决痛点硬件依赖导致单元测试困难效果可以通过Mock适配器进行测试5. 增强系统灵活性解决痛点硬件更换需要大量修改业务代码效果更换硬件只需提供新适配器业务层无需改动典型应用场景1. 硬件抽象层HAL// 为不同MCU提供统一外设接口 typedef struct { void (*gpio_set)(uint8_t pin, uint8_t state); void (*uart_send)(uint8_t* data, uint32_t len); } HAL_Interface; // STM32适配器 const HAL_Interface stm32_hal {stm32_gpio_set, stm32_uart_send}; // ESP32适配器 const HAL_Interface esp32_hal {esp32_gpio_set, esp32_uart_send};2. 协议转换器UART ↔ USBI2C ↔ SPI自定义协议 ↔ 标准协议如Modbus3. 数据格式适配大端序 ↔ 小端序浮点数 ↔ 定点数不同精度数据转换4. 新旧系统兼容遗留系统接口现代化不同版本固件接口兼容适配器模式vs其他模式模式关注点嵌入式示例适配器模式接口转换不同传感器接口统一外观模式接口简化复杂硬件操作封装为简单API桥接模式接口分离显示驱动与图形算法的解耦实现注意事项性能考量适配器可能引入额外函数调用开销在实时性要求高的场景需要评估内存占用每个适配器需要存储函数指针表在资源紧张系统中需权衡错误处理适配器应妥善处理被适配者的错误并转换为目标接口的错误码适配器模式是嵌入式系统集成和兼容性设计的利器特别适合需要整合多种硬件组件或维护不同版本兼容性的项目