当前位置: 首页 > news >正文

C语言实现状态模式

状态模式(State Pattern)的核心是允许对象在内部状态改变时改变其行为,使对象看起来好像修改了它的类。在C语言中,可以通过状态结构体(封装不同状态的行为)+ 上下文结构体(持有当前状态并委托行为) 实现:上下文将行为委托给当前状态对象,状态变化时只需切换上下文持有的状态指针。

C语言实现状态模式的思路

  1. 状态接口(State):定义所有具体状态的统一行为接口(函数指针),如handle(处理事件)。
  2. 具体状态(Concrete State):实现状态接口,封装对应状态下的具体行为,并在适当时候触发状态转换。
  3. 上下文(Context):持有当前状态的指针,提供统一接口供客户端调用,将具体行为委托给当前状态,同时允许状态切换。

示例:电梯状态管理(运行、停止、开门、关门)

电梯有多种状态(停止、运行、开门、关门),不同状态下对同一事件(如按开门键)的响应不同。用状态模式管理电梯状态转换和行为。

步骤1:定义状态接口和上下文
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 前向声明上下文,避免循环依赖
typedef struct Elevator Elevator;// 状态接口:定义电梯在不同状态下的行为
typedef struct State {// 处理开门事件void (*open)(struct State* self, Elevator* elevator);// 处理关门事件void (*close)(struct State* self, Elevator* elevator);// 处理运行事件void (*run)(struct State* self, Elevator* elevator);// 处理停止事件void (*stop)(struct State* self, Elevator* elevator);// 状态名称(用于打印)char name[20];
} State;
步骤2:实现上下文(电梯)

上下文持有当前状态,提供触发事件的接口,并允许状态切换。

// 上下文:电梯
typedef struct Elevator {State* current_state; // 当前状态int floor;            // 当前楼层
} Elevator;// 电梯初始化
void elevator_init(Elevator* elevator, State* initial_state) {elevator->current_state = initial_state;elevator->floor = 1; // 初始在1楼printf("电梯初始化,初始状态:%s(%d楼)\n", initial_state->name, elevator->floor);
}// 触发开门事件(委托给当前状态)
void elevator_open(Elevator* elevator) {printf("\n触发开门...\n");elevator->current_state->open(elevator->current_state, elevator);
}// 触发关门事件
void elevator_close(Elevator* elevator) {printf("\n触发关门...\n");elevator->current_state->close(elevator->current_state, elevator);
}// 触发运行事件
void elevator_run(Elevator* elevator) {printf("\n触发运行...\n");elevator->current_state->run(elevator->current_state, elevator);
}// 触发停止事件
void elevator_stop(Elevator* elevator) {printf("\n触发停止...\n");elevator->current_state->stop(elevator->current_state, elevator);
}// 切换电梯状态(由具体状态调用)
void elevator_change_state(Elevator* elevator, State* new_state) {elevator->current_state = new_state;printf("状态切换为:%s\n", new_state->name);
}
步骤3:实现具体状态(停止、运行、开门、关门)

每个状态实现State接口,定义该状态下对事件的响应,并在满足条件时切换到其他状态。

3.1 停止状态(电梯静止在某楼层)
// 前向声明其他状态,用于状态转换
extern State stopping_state;
extern State running_state;
extern State opening_state;
extern State closing_state;// 具体状态1:停止状态
static void stop_open(State* self, Elevator* elevator) {// 停止状态下可以开门printf("电梯在%d楼停止状态,执行开门...", elevator->floor);elevator_change_state(elevator, &opening_state); // 切换到开门状态
}static void stop_close(State* self, Elevator* elevator) {// 停止状态下关门无意义printf("电梯已停止且门关闭,无需关门\n");
}static void stop_run(State* self, Elevator* elevator) {// 停止状态下可以运行printf("电梯在%d楼停止状态,开始运行...", elevator->floor);elevator->floor = 5; // 模拟运行到5楼elevator_change_state(elevator, &running_state); // 切换到运行状态
}static void stop_stop(State* self, Elevator* elevator) {// 已在停止状态printf("电梯已处于停止状态\n");
}// 初始化停止状态
State stopping_state = {.open = stop_open,.close = stop_close,.run = stop_run,.stop = stop_stop,.name = "停止"
};
3.2 运行状态(电梯正在移动)
// 具体状态2:运行状态
static void run_open(State* self, Elevator* elevator) {// 运行中不能开门printf("电梯运行中,禁止开门\n");
}static void run_close(State* self, Elevator* elevator) {// 运行中门已关闭,无需关门printf("电梯运行中,门已关闭\n");
}static void run_run(State* self, Elevator* elevator) {// 已在运行状态printf("电梯已处于运行状态\n");
}static void run_stop(State* self, Elevator* elevator) {// 运行状态下可以停止printf("电梯从%d楼停止运行...", elevator->floor);elevator_change_state(elevator, &stopping_state); // 切换到停止状态
}// 初始化运行状态
State running_state = {.open = run_open,.close = run_close,.run = run_run,.stop = run_stop,.name = "运行"
};
3.3 开门状态(电梯门打开)
// 具体状态3:开门状态
static void open_open(State* self, Elevator* elevator) {// 已在开门状态printf("电梯门已打开\n");
}static void open_close(State* self, Elevator* elevator) {// 开门状态下可以关门printf("电梯门开始关闭...");elevator_change_state(elevator, &closing_state); // 切换到关门状态
}static void open_run(State* self, Elevator* elevator) {// 门开着不能运行printf("电梯门未关闭,无法运行\n");
}static void open_stop(State* self, Elevator* elevator) {// 开门状态下已停止printf("电梯门打开,已处于停止状态\n");
}// 初始化开门状态
State opening_state = {.open = open_open,.close = open_close,.run = open_run,.stop = open_stop,.name = "开门"
};
3.4 关门状态(电梯门关闭中)
// 具体状态4:关门状态
static void close_open(State* self, Elevator* elevator) {// 关门中可以重新开门printf("电梯门停止关闭,开始打开...");elevator_change_state(elevator, &opening_state); // 切换到开门状态
}static void close_close(State* self, Elevator* elevator) {// 已在关门状态printf("电梯门已关闭\n");
}static void close_run(State* self, Elevator* elevator) {// 门关闭后可以运行printf("电梯门关闭完成,开始运行...");elevator->floor = 3; // 模拟运行到3楼elevator_change_state(elevator, &running_state); // 切换到运行状态
}static void close_stop(State* self, Elevator* elevator) {// 关门后进入停止状态printf("电梯门关闭完成,停止不动...");elevator_change_state(elevator, &stopping_state); // 切换到停止状态
}// 初始化关门状态
State closing_state = {.open = close_open,.close = close_close,.run = close_run,.stop = close_stop,.name = "关门"
};
步骤4:使用状态模式

客户端通过上下文(电梯)触发事件,无需关心具体状态,状态转换由状态对象内部处理。

int main() {// 创建电梯(初始状态为停止)Elevator elevator;elevator_init(&elevator, &stopping_state);// 模拟电梯操作流程elevator_open(&elevator);    // 停止→开门elevator_close(&elevator);   // 开门→关门elevator_run(&elevator);     // 关门→运行elevator_stop(&elevator);    // 运行→停止elevator_run(&elevator);     // 停止→运行elevator_open(&elevator);    // 运行中开门(禁止)elevator_stop(&elevator);    // 运行→停止return 0;
}

输出结果

电梯初始化,初始状态:停止(1楼)触发开门...
电梯在1楼停止状态,执行开门...状态切换为:开门触发关门...
电梯门开始关闭...状态切换为:关门触发运行...
电梯门关闭完成,开始运行...状态切换为:运行触发停止...
电梯从3楼停止运行...状态切换为:停止触发运行...
电梯在3楼停止状态,开始运行...状态切换为:运行触发开门...
电梯运行中,禁止开门触发停止...
电梯从5楼停止运行...状态切换为:停止

核心思想总结

  1. 行为与状态绑定:每个状态封装了该状态下的行为(如stopping_stateopen方法允许开门),避免了用if-elseswitch判断状态的硬编码。
  2. 状态转换清晰:状态转换逻辑由具体状态对象控制(如closing_staterun方法切换到running_state),职责明确。
  3. 扩展性好:新增状态(如“故障状态”)只需实现State接口,无需修改上下文或其他状态代码,符合开放-封闭原则
  4. 上下文与状态解耦:上下文(电梯)只需委托行为给当前状态,无需知道具体状态的实现,降低耦合。

C语言通过结构体封装状态行为和状态转换逻辑,结合上下文委托机制,完美实现了状态模式的核心。这种模式适合处理对象行为随状态变化而变化的场景(如订单状态、设备状态、游戏角色状态等)。

http://www.dtcms.com/a/565429.html

相关文章:

  • SQLite 常用函数
  • 青岛seo网站推广广告电商
  • app软件小程序网站建设wordpress jetpack 慢
  • 2G2核服务器安装ES
  • 大规模图片列表性能优化:基于 IntersectionObserver 的懒加载与滚动加载方案
  • CANN算子开发实战:从矩阵乘法到高性能优化
  • 网站推广教程分享wordpress 阴影
  • 从协议规范和使用场景探讨为什么SmartMediaKit没有支持DASH
  • 【工程开发】GLM-4.1V调试
  • Fiddler抓包手机和部分app无法连接网络问题
  • 【开题答辩全过程】以 二手咸鱼手机交易平台为例,包含答辩的问题和答案
  • 云真机和云手机的区别
  • 成都市那里有网站建设制作公司Wordpress 启动邮件
  • 东莞建网站的公司数据分析师资格证书怎么考
  • Spring Boot MVC 实战指南
  • 蓝牙钥匙 第36次 汽车共享与分时租赁场景核心技术解析:从预约到多用户无缝切换
  • 教育行业网站建设方案虫部落是谁做的网站
  • Tesseract OCR 配置参数详解
  • 网站权重对应的等级5944免费空间上搭建网站
  • DevOps(devops/k8s/docker/Linux)学习笔记-4
  • 建立网站的程序武威市住房和建设局网站
  • 微服务面试题(14题)
  • 软件造价评估优秀案例:某大型能源企业数字化项目费用编制与后评价体系研究
  • mysql uuid()
  • 页面好看的蛋糕网站软件开发应该学什么专业
  • QtitanNavigation助力能源数字化转型:打造清晰可控的系统导航体验
  • 基于知识图谱(Neo4j)和大语言模型(LLM)的图检索增强(GraphRAG)的植物病害知识问答系统(vue+flask+AI算法)
  • 数据库之多版本控制MVCC
  • CentOS7安装Docker和Mysql
  • PyTorch实战指南:从零搭建计算机视觉模型的完整流程