痛点描述
传统嵌入式代码中,经常出现大量的if-else或switch-case判断不同算法或硬件配置:
// 传统做法:条件分支臃肿
void sensor_control(SensorType type) {
if (type == TEMPERATURE_I2C) {
i2c_init();
i2c_read_temp();
} else if (type == HUMIDITY_UART) {
uart_init();
uart_read_humidity();
} else if (type == PRESSURE_SPI) {
spi_init();
spi_read_pressure();
}
// 新增传感器需要修改此处,违反开闭原则
}
策略模式解决方案
// 使用策略模式后
void sensor_control(const SensorStrategy *strategy) {
strategy->init();
strategy->read_data();
}
// 新增传感器只需添加新策略,无需修改现有代码
2. 运行时动态配置
痛点描述
嵌入式系统经常需要根据环境变化(如电池电量、网络状态、外设连接)动态调整行为:
- 电池电量低时,从高性能算法切换到节能算法
- 传感器故障时,切换到备用数据处理方案
- 通信信号弱时,切换调制方式或协议
传统实现的困境
// 硬编码配置,无法动态适应
void communication_setup(void) {
#ifdef POWER_SAVING_MODE
setup_low_power_protocol(); // 编译时确定,无法运行时切换
#else
setup_high_perf_protocol();
#endif
}
策略模式优势
// 根据电池电量动态切换
void update_communication_strategy(int battery_level) {
if (battery_level < 20) {
comm_set_strategy(&low_power_strategy); // 运行时切换
} else {
comm_set_strategy(&high_perf_strategy);
}
}
3. 硬件资源冲突管理
痛点描述
嵌入式系统中硬件资源(如DMA通道、定时器、中断)有限,多个功能可能竞争同一资源:
- UART和SPI共享同一DMA通道
- 不同传感器分时使用I2C总线
- 算法切换时需要重新配置外设
策略模式的资源管理
void comm_set_strategy(CommunicationManager *mgr,
const CommunicationStrategy *new_strategy) {
if (mgr->strategy) {
mgr->strategy->deinit(); // 释放当前硬件资源
}
mgr->strategy = new_strategy;
mgr->strategy->init(); // 初始化新硬件配置
}
// 确保资源安全切换,避免冲突
4. 测试和维护困难
痛点描述
嵌入式代码高度依赖硬件环境:
- 算法与硬件驱动紧耦合,难以单元测试
- 修改一个功能可能影响其他模块
- 不同硬件平台移植困难
策略模式的解耦效果
// 可独立测试每个策略
void test_uart_strategy(void) {
CommunicationStrategy *strategy = &uart_strategy;
strategy->init();
strategy->send(test_data, len); // 可Mock硬件层进行测试
strategy->deinit();
}
// 硬件平台移植时只需实现策略接口,不影响业务逻辑
5. 代码冗余和复用性差
痛点描述
相似功能在不同模块中重复实现:
// 模块A中的SPI操作
void module_a_spi_send(void) {
spi_cs_low();
spi_transmit(data);
spi_cs_high();
}
// 模块B中类似的SPI操作(但略有不同)
void module_b_spi_send(void) {
spi_cs_low();
delay(1); // 特殊延时要求
spi_transmit(data);
spi_cs_high();
}
策略模式的统一封装
// 通用SPI策略,支持差异化配置
const CommunicationStrategy spi_strategy_fast = {
.send = spi_send_fast // 无延时版本
};
const CommunicationStrategy spi_strategy_slow = {
.send = spi_send_slow // 带延时版本
};
// 避免代码重复,提高复用性
6. 系统可配置性差
痛点描述
传统嵌入式系统行为通常在编译时确定,无法根据用户需求或环境变化调整:
- 固定使用某种滤波算法
- 通信参数无法现场配置
- 功能扩展需要重新烧录固件
策略模式的动态性
// 通过配置表实现灵活的策略映射
typedef struct {
int scenario_id;
const CommunicationStrategy *strategy;
} StrategyConfig;
StrategyConfig config_table[] = {
{SCENARIO_HIGH_SPEED, &uart_strategy_1mbps},
{SCENARIO_LOW_POWER, &i2c_strategy_slow},
{SCENARIO_RELIABILITY, &spi_strategy_verified}
};
void apply_scenario(int scenario) {
// 根据场景ID动态切换策略
const CommunicationStrategy *strategy = find_strategy(scenario);
comm_set_strategy(&comm_mgr, strategy);
}
总结:策略模式解决的嵌入式核心痛点
| 痛点 | 传统方法的问题 | 策略模式的解决方案 |
|---|---|---|
| 条件分支复杂 | if-else嵌套难以维护 |
算法封装,消除条件判断 |
| 静态配置 | 编译时确定,无法适应变化 | 运行时动态切换 |
| 资源冲突 | 手动管理容易出错 | 自动化的资源初始化和释放 |
| 测试困难 | 硬件依赖导致难以测试 | 接口抽象,便于Mock测试 |
| 代码冗余 | 相似功能重复实现 | 策略复用,减少重复代码 |
| 扩展性差 | 修改影响范围大 | 符合开闭原则,易于扩展 |
策略模式本质上为嵌入式系统提供了**"算法即插件"的能力,非常适合需要灵活应对多种场景**的嵌入式应用场景。