1. 策略模式:算法自由切换的艺术
第一次在嵌入式项目中遇到需要动态切换通信协议的场景时,我对着满屏的if-else条件分支陷入了沉思。当项目需求从Modbus扩展到CANopen再到自定义协议时,代码已经臃肿到难以维护的程度。直到接触策略模式,才真正理解了"算法的热插拔"这个精妙比喻——就像电脑上的USB接口,协议处理算法可以随时插拔更换而不影响系统主体结构。
在C语言这种非面向对象的语言中实现策略模式,核心在于利用函数指针和结构体模拟多态特性。不同于Java或C++的接口机制,C语言需要开发者手动构建这种灵活性。下面这段典型实现展示了策略模式的基本骨架:
c复制typedef struct {
void (*algorithm)(void); // 策略接口
} Strategy;
void algorithmA_impl() { /* 具体策略A的实现 */ }
void algorithmB_impl() { /* 具体策略B的实现 */ }
Strategy createStrategyA() {
return (Strategy){.algorithm = algorithmA_impl};
}
Strategy createStrategyB() {
return (Strategy){.algorithm = algorithmB_impl};
}
关键提示:在嵌入式系统中,函数指针应尽量声明为静态类型以避免运行时开销,同时所有策略函数应保持相同的调用约定(calling convention)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. C语言实现策略模式的三种经典方式
2.1 函数指针结构体法
这是最接近面向对象思想的实现方式。我们定义一个包含操作集合的结构体,每种策略都实现自己的结构体实例。以数据加密算法为例:
c复制typedef struct {
void (*encrypt)(uint8_t* data, size_t len);
void (*decrypt)(uint8_t* data, size_t len);
uint32_t (*getKeySize)(void);
} CryptoStrategy;
// AES策略实现
void aes_encrypt(uint8_t* data, size_t len) { /*...*/ }
void aes_decrypt(uint8_t* data, size_t len) { /*...*/ }
uint32_t aes_key_size() { return 256; }
CryptoStrategy AES = {
.encrypt = aes_encrypt,
.decrypt = aes_decrypt,
.getKeySize = aes_key_size
};
// DES策略实现
void des_encrypt(uint8_t* data, size_t len) { /*...*/ }
/* 其他DES函数... */
CryptoStrategy DES = {
/* 初始化DES函数指针... */
};
这种方式的优势在于:
- 策略接口清晰可见
- 新增策略只需实现接口函数
- 运行时切换成本极低
2.2 查表法
适用于策略数量固定且已知的场景,比如通信协议转换器。我们预先建立策略ID与处理函数的映射表:
c复制typedef enum { PROTOCOL_MODBUS, PROTOCOL_CANOPEN, PROTOCOL_CUSTOM } ProtocolType;
typedef struct {
ProtocolType id;
void (*pack)(void* frame);
void (*parse)(void* frame);
bool (*validate)(void* frame);
} ProtocolStrategy;
ProtocolStrategy protocolStrategies[] = {
{PROTOCOL_MODBUS, modbus_pack, modbus_parse, modbus_validate},
{PROTOCOL_CANOPEN, canopen_pack, canopen_parse, canopen_validate},
/* 其他协议... */
};
ProtocolStrategy* getStrategy(ProtocolType type) {
for(int i=0; i<sizeof(protocolStrategies)/sizeof(pro
