在C语言中实现状态机模式(State Pattern)可以通过函数指针+状态结构体模拟面向对象的多态行为。以下是一个完整的示例,以电灯开关(On/Off)为例:
#include <stdio.h>
// 状态接口(模拟抽象类)
typedef struct State State;
struct State {
void (*handle)(void *context); // 处理函数指针
};
// 上下文(持有当前状态)
typedef struct {
State *current_state;
} Context;
// 具体状态:开
void on_state_handle(void *context);
State OnState = { .handle = on_state_handle };
// 具体状态:关
void off_state_handle(void *context);
State OffState = { .handle = off_state_handle };
//--- 状态行为实现 ---
void on_state_handle(void *context) {
Context *ctx = (Context *)context;
printf("灯已开,执行关闭操作\n");
ctx->current_state = &OffState; // 切换到关状态
}
void off_state_handle(void *context) {
Context *ctx = (Context *)context;
printf("灯已关,执行开启操作\n");
ctx->current_state = &OnState; // 切换到开状态
}
//--- 上下文操作 ---
void init_context(Context *ctx) {
ctx->current_state = &OffState; // 初始状态为关
}
void request(Context *ctx) {
ctx->current_state->handle(ctx); // 委托给当前状态处理
}
//--- 测试代码 ---
int main() {
Context ctx;
init_context(&ctx);
// 模拟用户操作
for (int i = 0; i < 4; i++) {
request(&ctx); // 每次请求触发状态转换
}
return 0;
}
输出结果:
灯已关,执行开启操作
灯已开,执行关闭操作
灯已关,执行开启操作
灯已开,执行关闭操作
关键设计解析:
- 状态接口(State)
- 使用函数指针
handle 模拟虚函数
- 所有具体状态必须实现该函数
- 具体状态(OnState/OffState)
- 全局单例状态对象(避免重复创建)
- 在
handle() 中实现状态转移逻辑
- 上下文(Context)
- 持有
current_state 指针指向当前状态
request() 方法委托给状态对象处理
- 状态转移
- 在状态处理函数中直接修改
context->current_state
- 符合开闭原则:新增状态无需修改上下文
扩展新状态步骤(以添加闪烁状态为例):
// 1. 定义新状态
void blinking_state_handle(void *context);
State BlinkingState = { .handle = blinking_state_handle };
// 2. 实现行为逻辑
void blinking_state_handle(void *context) {
Context *ctx = (Context *)context;
printf("闪烁中,切换到关闭状态\n");
ctx->current_state = &OffState;
}
// 3. 在现有状态中添加转移(如在OnState中)
void on_state_handle(void *context) {
/* ... */
if(需要闪烁) ctx->current_state = &BlinkingState;
}
优势:
- 解耦状态逻辑:每个状态独立封装行为
- 消除条件分支:避免复杂的switch-case语句
- 可扩展性:符合开放封闭原则
- 状态转移显式化:转移逻辑在状态内部明确声明
经典应用场景:TCP连接状态、工控系统流程、游戏AI行为、协议解析器等需要清晰状态转换逻辑的系统。
|