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

嵌入式C语言编程:策略模式、状态模式和状态机的应用

1. 概述

在没有面向对象语法的C语言中,策略(Strategy)模式和状态(State)模式都通过“上下文 + 接口”组合来模拟多态。

它们在代码结构上几乎一致,但设计意图和应用场景却差异很大。

本文将结合典型的滤波算法和USB设备示例,深入解析两者的实现差异与选型建议。

2. 两种模式介绍

  • 策略模式:将一组算法封装起来,调用者在运行时决定使用哪一种,关注“如何做”。

策略模式类图

sensor_t
+filter_strategy_t *strat
+data[128]
«interface»
filter_strategy_t
+filter(buf, len)
mean_strat
kalman_strat
  • 状态模式:让对象在内部状态变化时自行切换行为,关注“何时做、做什么”。

状态模式类图

usb_dev_t
+usb_state_t *state
«interface»
usb_state_t
+handle(dev, evt)
st_disconnected
st_connecting
st_ready
st_error

状态转换图

EVT_PLUG_IN
EVT_ENUM_OK
EVT_ENUM_FAIL
Disconnected
Connecting
Ready
Error

3. 实现结构其实类似

// 通用接口类型(vtable)
typedef struct {void (*action)(void *ctx, int evt);
} module_iface_t;// 通用上下文
typedef struct {const module_iface_t *iface;  // 指向当前策略或状态void *state_data;             // 具体实例数据
} module_ctx_t;

上述结构在策略和状态模式下均可重用:仅需替换 action 策略函数或 handle_event 状态函数。

4. 策略模式详解

4.1 典型场景

一个传感器需要根据功耗或精准度要求,动态选用不同滤波算法。

4.2 代码示例

// 策略接口
typedef struct {void (*filter)(int *buf, int len);
} filter_strategy_t;// 上下文
typedef struct {const filter_strategy_t *strat;int data[128];
} sensor_t;// 均值滤波
void mean_filter(int *buf, int len) { /* ... */ }
const filter_strategy_t mean_strat = { .filter = mean_filter };// 卡尔曼滤波
void kalman_filter(int *buf, int len) { /* ... */ }
const filter_strategy_t kalman_strat = { .filter = kalman_filter };// 应用层切换策略
void sensor_process(sensor_t *s) {if (is_low_power()) {s->strat = &mean_strat;} else {s->strat = &kalman_strat;}s->strat->filter(s->data, 128);
}

4.3 策略模式特点

  • 切换由外部决定
  • 上下文仅负责调用,不关心何时切换
  • 适合算法族、可插拔的行为

5. 状态模式详解

5.1 典型场景

一个USB设备在不同生命周期阶段:断开、连接中、就绪、错误,各阶段有不同处理逻辑,并能自动流转。

5.2 代码示例

typedef struct usb_dev_s usb_dev_t;// 状态接口
typedef struct {void (*handle)(usb_dev_t *dev, int evt);
} usb_state_t;// 上下文
struct usb_dev_s {const usb_state_t *state;// 设备相关数据
};// 断开状态
void st_disconnected(usb_dev_t *d, int evt) {if (evt == EVT_PLUG_IN) {d->state = &st_connecting;start_enumeration();}
}
const usb_state_t st_disconnected = { .handle = st_disconnected };// 连接中状态
void st_connecting(usb_dev_t *d, int evt) {if (evt == EVT_ENUM_OK) {d->state = &st_ready;} else if (evt == EVT_ENUM_FAIL) {d->state = &st_error;}
}
const usb_state_t st_connecting = { .handle = st_connecting };// 事件分发
void usb_event(usb_dev_t *d, int evt) {d->state->handle(d, evt);
}

6. 策略模式与状态模式的状态机化融合

6.1 概述

实现了策略模式与状态模式的深度融合,既能在运行时无缝切换不同流程,也能在状态内部灵活替换子算法,为复杂嵌入式控制系统提供高内聚、低耦合、可配置的可复用框架。

在嵌入式系统(如固件升级、多协议网关、自适应控制)中,通常面临两类变化点:

  • 横向变化:整条业务流程需要整体替换(例如升级流程与正常流程)。
  • 纵向变化:流程内部某一状态的子算法需要动态替换(例如根据网络质量切换可靠传输与快速传输)。

如果采用传统的switch-case 实现,常会引发以下困境:

  • 新增流程时需要阅读理解整份代码。
  • 运行时切换流程通常需重启或清零全局变量,造成业务中断。
  • 难以针对单一流程进行单元测试证。

6.2 策略-状态两级抽象

实现了策略模式与状态模式的深度融合,既能在运行时无缝切换不同流程,也能在状态内部灵活替换子算法,为复杂嵌入式控制系统提供高内聚、低耦合、可配置的可复用框架。

第一级:整状态机作为策略

将完整状态机(含状态表、变量、定时器与转移逻辑)封装为统一策略接口 sm_strategy_t
Context 在运行时只需持有对该接口的指针,即可灵活切换整个状态机实现。

sm_ctx_t fsm;
fsm.ops = use_upgrade ? &sm_upgrade : &sm_normal;
fsm.ops->init(&fsm);

第二级:状态内部再嵌策略

在某个具体状态的处理函数中,根据运行时条件动态注入子策略,以替换子算法或业务动作。

/* 在 Transferring 状态中,根据网络质量选择子策略 */
ctx->sub = is_lossy() ? &reliable_xfer_strategy : &fast_xfer_strategy;
ctx->sub->chunk_size = calc_chunk_size(ctx->rtt);
ctx->sub->send(ctx->sub, evt);

两级策略各自独立:

  • 第一级解决“流程级”整体切换。
  • 第二级解决“状态级”内部微调。

6.3 静态结构

sm_ctx_t
+const sm_strategy_t *ops
+void *state_data
«interface»
sm_strategy_t
+init(sm_ctx_t*)
+dispatch(sm_ctx_t*, int)
sm_normal
sm_upgrade

6.4 运行时视图

选择策略
normal
upgrade
Application
strategy
sm_normal FSM
sm_upgrade FSM
state1
state2
stateA
stateB

6.5 关键实现细节

策略接口定义

typedef struct sm_ctx_s sm_ctx_t;
typedef struct {void (*init)(sm_ctx_t*);void (*dispatch)(sm_ctx_t*, int);
} sm_strategy_t;

运行时上下文

struct sm_ctx_s {const sm_strategy_t *ops;   /* 当前流程策略 */void                *state_data;
};

零停机切换

通过原子写入指针即可完成业务流程切换,无需中断或重启。

void switch_strategy(sm_ctx_t *ctx, const sm_strategy_t *new_ops)
{new_ops->init(ctx);ctx->ops = new_ops;    /* 原子赋值,零停机 */
}

状态内子策略示例

typedef struct {void (*send)(const void *self, int event);size_t chunk_size;
} xfer_strategy_t;static void st_transferring(sm_ctx_t *ctx, int evt)
{xfer_strategy_t *sub = select_xfer_strategy(ctx->rtt);sub->chunk_size = calc_chunk(ctx->rtt);sub->send(sub, evt);
}
http://www.lryc.cn/news/612603.html

相关文章:

  • 蓝凌EKP产品:列表查询性能优化全角度
  • Git 文件删除操作指南:管理与恢复已删除文件
  • 合约收款方式,转账与问题安全
  • 「耘•学社」耘少年第五期学能突破导师制领袖特训营,圆满落幕
  • 计算机视觉前言-----OpenCV库介绍与计算机视觉入门准备
  • 解决Git提交人信息默认全局化问题:让提交人自动关联当前用户
  • Element Plus实现分页查询
  • 【PHP 中的 `use` 关键字完全指南】
  • 数码论坛|基于SprinBoot+vue的数码论坛系统(源码+数据库+文档)
  • Redis为什么要引入多线程?
  • Beelzebub靶机
  • 防火墙环境下的全网服务器数据自动化备份平台搭建:基于 rsync 的完整实施指南
  • Java基础学习1(Java语言概述)
  • spring cache(二)核心接口
  • 浏览器渲染与GPU进程通信图解
  • ubuntu 2024 安装拼音输入法
  • 纪念《信号与系统》拉普拉斯变换、Z变换之前内容学完
  • 迭代器与生成器:Python 中的高效数据遍历机制
  • 现代制冷系统核心技术解析:从四大件到智能控制的关键突破
  • QDataStream入门
  • LeetCode每日一题,2025-8-7
  • JSON、JSONObject、JSONArray详细介绍及其应用方式
  • Self-RAG:基于自我反思的检索增强生成框架技术解析
  • 【感知机】感知机(perceptron)学习策略
  • 阿里云polardb-x 2.0迁移至华为云taurusdb
  • 【感知机】感知机(perceptron)模型与几何解释
  • MySQL数据库索引及底层数据结构
  • 2025国赛数学建模C题详细思路模型代码获取,备战国赛算法解析——决策树
  • 软件架构:系统结构的顶层设计与战略约束
  • Maven入门到精通