嵌入式编程
跳转到“嵌入式编程”核心特征:
- 专用性:嵌入式系统为特定任务设计,不像通用计算机那样需要处理各种应用
- 资源受限:在处理器性能、内存容量、存储空间、功耗等方面都有严格限制
- 实时性要求:许多嵌入式系统需要在规定时间内响应外部事件
- 可靠性要求高:系统必须长期稳定运行,故障可能导致严重后果
C结构化编程、面向对象编程:
- 系统复杂度:简单系统用结构化,复杂系统考虑OOP
- 资源限制:极度受限环境倾向结构化
- 团队经验:考虑开发团队的技术背景
- 维护需求:长期维护的项目可能更适合OOP
Harmony的嵌入式编程
跳转到“Harmony的嵌入式编程”Harmony/ERT是IBM Rational开发的嵌入式实时系统开发过程。核心创新在于采用**三层并行开发周期: 1. 宏周期(Macrocycle)
- 整个项目的时间线和主要里程碑
- 关注整体架构和主要里程碑交付
2. 微周期(Microcycle)
- 重复的短期开发迭代(通常4-6周)
- 每个微周期产出可测试的增量功能
3. 纳周期(Nanocycle)
- 日常的快速迭代开发
- 测试驱动的持续集成
设计标准分级与开发流程
跳转到“设计标准分级与开发流程”设计模式是“对经常出现的问题的通解”,如果它仅适用于单一应用域,那么它很可能是一个分析模式。
计标准分级:性能标准、可靠性标准、可维护性标准。

Harmony过程中的设计模式采用Gamma等人提出的四要素描述:
- 名字:模式的标识符
- 目的:解决什么问题
- 解决方案:模式的结构和行为
- 效果:使用模式的利弊权衡
设计模式的应用原则:
- 模式是经过验证的解决方案模板
- 需要根据具体场景调整和定制
- 关注模式带来的权衡而非盲目应用

开发流程建议:
- 识别问题模式
- 评估设计方案
- 选择合适模式
- 定制化实现
- 验证设计有效性

访问硬件的设计模式
跳转到“访问硬件的设计模式”硬件代理模式
跳转到“硬件代理模式”
HardwareProxy 的 4 个关键组件:
- 设备地址管理:deviceAddr 可以是内存地址(0x3F8)、端口号或设备文件句柄
- 初始化序列:检测设备存在 → 设置默认参数 → 分配资源
- 配置管理:统一接口设置波特率、数据位、校验位等硬件参数
- 数据转换:完成位序转换、字节序调整、协议封装/解封装
硬件代理模式(Hardware Proxy Pattern)创建软件单元负责访问硬件的一部分。将硬件封装到类或结构体中。
抽象:硬件代理模式使用类(或结构体)封装所有硬件设备访问,无论其硬件接口是交互的。 问题:如果位编码、内存地址或连接技术改变,那么每个客户必须查看和修改。通过提供位于客户和硬件之间的代理,就极大地限制了硬件的影响,从而减少这种的修改。为了易于维护,客户应该不会意识到设备使用的位编码、加密和压缩,这些细节将会通过硬件代理的内部私有方法管理。 模式结构:可能有很多客户,但是每个被控设备仅有单一的硬件代理。代理包括公有和私有方法,封装函数和数据。在图中各表示为void*,但是它将会为设备适当地被予类型。
应用场景
- 传感器接口统一化(温度、压力、位置传感器)
- 执行器控制抽象(电机、继电器、LED)
- 设备驱动的用户态接口封装
- 硬件抽象层(HAL)的核心组件
工业控制系统 :
- PLC 与现场设备的通信代理
- 实时系统中的硬件访问控制
设计原则与最佳实践
- 单一职责:每个代理类只负责一种硬件设备
- 错误处理:完善的异常与硬件故障检测
- 线程安全:多线程同步访问控制
- 资源管理:自动释放硬件资源,防止泄漏
- 性能优化:缓存、批量、异步 I/O
- 可测试性:提供模拟硬件接口用于单元测试
与其他设计模式的关系:
- 适配器模式:把不兼容硬件接口转成标准接口
- 外观模式:为复杂硬件子系统提供简化接口
- 单例模式:每类硬件只持一个代理实例
- 策略模式:按厂商替换不同通信策略
- 观察者模式:硬件状态变化事件通知
- 工厂模式:按设备类型创建代理对象
示例: 马达代理的应用层以硬件接口独立的方式提供服务。马达管理方法:
- configure() — 这个方法设置马达的内存映射地址与旋转臂的长度。这个方法必须首先调用。
- disable() — 这个方法关闭马达,但是保持设置的值原封不动。
- enable() — 这个方法使用目前设定的值启动马达。
- initialize() — 这个方法使用默认的设置值(off)启动马达。
马达状态方法:
- accessMotorDirection() — 这个方法返回当前马达的方向(关闭,向前或反向)。
- accessMotorSpeed() — 这个方法返回马达的速度。
马达控制方法:
- writeMotorSpeed() — 这个方法设置马达的速度并且调整旋转臂的长度(如果设置了的话)。
马达错误管理方法:
- clearErrorStatus() — 这个方法清除所有的错误位。
- accessMotorStatus() — 这个方法返回错误状态。
内部数据格式化方法(私有) 这些方法不提供给客户,但是内部使用时在原始格式和表示格式间转换数据。
- marshal() — 把表示(客户)数据格式转换为本地(马达)格式。
- unmarshal() — 把原始(马达)数据格式转换为表示(客户)格式。
#ifndef HWProxyExample_H#define HWProxyExample_H
struct MotorController;struct MotorData;struct MotorDisplay;struct MotorProxy;
typedef enum DirectionType { NO_DIRECTION, FORWARD, REVERSE} DirectionType;#endif#ifndef MotorData_H#define MotorData_H
#include "HWProxyExample.h"typedef struct MotorData MotorData;
struct MotorData { unsigned char on_off; DirectionType direction; unsigned int speed; unsigned char errorStatus; unsigned char noPowerError; unsigned char noTorqueError; unsigned char BITError; unsigned char overTemperatureError; unsigned char reservedError1; unsigned char reservedError2; unsigned char unknownError;};#endif#ifndef MotorProxy_H#define MotorProxy_H
#include "HWProxyExample.h"#include "MotorData.h"
/* MotorProxy类 */typedef struct MotorProxy MotorProxy;
/* 这是电机硬件的代理。*//* 注意电机速度根据旋转臂的长度进行调整 *//* 以保持旋转臂末端的恒定速度。*/
struct MotorProxy { unsigned int* motorAddr; unsigned int rotaryArmLength;};
void MotorProxy_Init(MotorProxy* const me);void MotorProxy_Cleanup(MotorProxy* const me);
DirectionType* MotorProxy_accessMotorDirection(MotorProxy* const me);unsigned int MotorProxy_accessMotorSpeed(MotorProxy* const me);unsigned int MotorProxy_accessMotorState(MotorProxy* const me);
/* 清除所有错误位 */void MotorProxy_clearErrorStatus(MotorProxy* const me);
/* 必须首先调用配置,因为它设置了 *//* 设备的地址。*/void MotorProxy_configure(MotorProxy* const me, unsigned int length, unsigned int* location);
/* 关闭电机但保留原始设置 */void MotorProxy_disable(MotorProxy* const me);
/* 使用默认状态启动硬件但保留所有其他设置 *//* 单独启动硬件 */void MotorProxy_enable(MotorProxy* const me);
/* 根据已知的默认状态初始化。*//* 关闭硬件,将速度和方向设置为电机 */void MotorProxy_initialize(MotorProxy* const me);
/* 创建和销毁函数 */MotorProxy* MotorProxy_Create(void);void MotorProxy_Destroy(MotorProxy* const me);
#endif#include "MotorProxy.h"
/* MotorProxy类 *//* 该函数获取MotorData结构并创建 *//* 特定于设备的无符号整数原生格式。*/
static unsigned int marshal(MotorProxy* const me, const struct MotorData* mData);
static struct MotorData* unmarshal(MotorProxy* const me, unsigned int encodedMData);
void MotorProxy_Init(MotorProxy* const me){ // 初始化代码}
void MotorProxy_Cleanup(MotorProxy* const me){ // 清理代码}
DirectionType* MotorProxy_accessMotorDirection(MotorProxy* const me){ MotorData mData; if(!me->motorData) return 0; mData = unmarshal(me->motorAddr); return mData.direction;}
unsigned int MotorProxy_accessMotorSpeed(MotorProxy* const me){ MotorData mData; if(!me->motorData) return 0; mData = unmarshal(me->motorAddr); return mData.speed;}
unsigned int MotorProxy_accessMotorState(MotorProxy* const me){ MotorData mData; if(!me->motorData) return 0; mData = unmarshal(me->motorAddr); return mData.errorStatus;}
void MotorProxy_clearErrorStatus(MotorProxy* const me){ if(!me->motorData) return; *me->motorAddr &= 0xFF;}
void MotorProxy_configure(MotorProxy* const me, unsigned int length, unsigned int* location){ me->rotaryArmLength = length; me->motorAddr = location;}
void MotorProxy_disable(MotorProxy* const me){ // 与enable位设置为除了enable位 if(!me->motorData) return; me->motorAddr &= 0xFFFE;}
void MotorProxy_enable(MotorProxy* const me){ if(!me->motorData) return; *me->motorAddr |= 1;}
void MotorProxy_initialize(MotorProxy* const me){ MotorData mData; if(!me->motorData) return; mData.on_off = 1; mData.direction = 0; mData.speed = 0; mData.errorStatus = 0; mData.noPowerError = 0; mData.noTorqueError = 0; mData.BITError = 0; mData.overTemperatureError = 0; mData.reservedError1 = 0; mData.reservedError2 = 0; Data.unknownError = 0; *me->motorAddr = marshal(mData);}
void MotorProxy_writeMotorSpeed(MotorProxy* const me, const DirectionType* direction, unsigned int speed){ MotorData mData; double dPI, dArmLength, dSpeed, dAdjSpeed;
if(!me->motorData) return; mData = unmarshal(*me->motorAddr); mData.direction = direction;
// 好的,让我们根据旋转臂长度进行一些数学调整 if(me->rotaryArmLength > 0){ dSpeed = speed; dArmLength = me->rotaryArmLength; dAdjSpeed = dSpeed / 2.0 / 3.14159 / dArmLength * 10.0; mData.speed = (int)dAdjSpeed; } else{ mData.speed = speed; }
*me->motorData = marshal(mData); return;}
static unsigned int marshal(MotorProxy* const me, const struct MotorData* mData){ unsigned int deviceCmd;
deviceCmd = 0; // 设置所有位为零 if(mData.on_off) deviceCmd |= 1; // 在适当的位中设置OR if(mData.direction == FORWARD) deviceCmd |= (2 << 1); else if(mData.direction == REVERSE) deviceCmd |= (1 << 1);
if(mData.speed < 32 && mData.speed >= 0) deviceCmd |= mData.speed << 3;
if(mData.errorStatus) deviceCmd |= 1 << 8; if(mData.noPowerError) deviceCmd |= 1 << 9; if(mData.noTorqueError) deviceCmd |= 1 << 10; if(mData.BITError) deviceCmd |= 1 << 11; if(mData.overTemperatureError) deviceCmd |= 1 << 12; if(mData.reservedError1) deviceCmd |= 1 << 13; if(mData.reservedError2) deviceCmd |= 1 << 14; if(mData.unknownError) deviceCmd |= 1 << 15;
return deviceCmd;}
static struct MotorData* unmarshal(MotorProxy* const me, unsigned int encodedMData){ MotorData mData; int temp;
mData.on_off = encodedMData & 1; temp = (encodedMData & (3 << 1)) >> 1; if(temp == 1) mData.direction = REVERSE; else if(temp == 2) mData.direction = FORWARD; else mData.direction = NO_DIRECTION;
mData.speed = encodedMData & (31 << 3); mData.errorStatus = encodedMData & (1 << 8); mData.noPowerError = encodedMData & (1 << 9); mData.noTorqueError = encodedMData & (1 << 10); mData.BITError = encodedMData & (1 << 11); mData.overTemperatureError = encodedMData & (1 << 12); mData.reservedError1 = encodedMData & (1 << 13); mData.reservedError2 = encodedMData & (1 << 14); mData.unknownError = encodedMData & (1 << 15);
return mData;}
MotorProxy* MotorProxy_Create(void){ MotorProxy* me = (MotorProxy*) malloc(sizeof(MotorProxy)); if(me!=NULL){ MotorProxy_Init(me); } return me;}
void MotorProxy_Destroy(MotorProxy* const me){ if(me!=NULL){ MotorProxy_Cleanup(me); } free(me);}硬件适配器模式 (Hardware Adapter Pattern)
跳转到“硬件适配器模式 (Hardware Adapter Pattern)”硬件适配器模式提供一种方法,使已经存在硬件接口能适应应用期望。该模式是适配器模式的简单衍生。
当两块硬件长得差不多、接口却不一样时,给它套个“翻译壳”,让上层软件永远只说一句“给我数据”,而不用管底下到底是 A 厂还是 B 厂的传感器。
**抽象**:当应用需要或使用一个接口而实际硬件提供另一种时,**硬件适配器模式**(Hardware Adapter Pattern)非常实用。模式创建元素在两个接口之间进行转换。
问题:执行相似功能的硬件往往有相似的接口,但通常它们需要的信息和服务的集合不同。当转换来自或发给实际硬件接口的请求时,创建适配器提供客户期望的接口,而不是重写硬件设备的客户来使用提供的接口。当你的硬件需要系统语义需求但是有不兼容的接口时,硬件适配器模式是很实用的。该模式的目标是,当使用一个硬件设计或实现替换另一个时,最少化返工代码。
模式结构:
效果:
该模式允许使用各种硬件代理,并且在不同的应用中使用与它们相关的硬件设备。同时允许已有的应用不同的硬件设备,而不需要做任何改变。关键是适配器提供连接客户来将硬件代理配置应用时。这意味着它将会更易用、不易出错或为应用更快速改变硬件设备,或者在一个新的应用中重用一个已存在的硬件设备。
示例: 该实例显示监测氧气浓度和氧气流量的系统,这样例子可能在医疗呼吸机上找到。这里显示了两个客户。Gas Display客户为相关医护人员显示这些数据。Gas Mixer客户编将这些数据用于气体输送闭合循环控制。

实现两者均使用iO2Sensor的接口,如iO2Sensor接口所示。客户期望的两个服务包括:
gimmeO2Conc():它返回一个0~100范围的整数,以及gimmeO2Flow():返回以cc/min为单位的整数类型
系统可以与任意两个物理传感器交互。这些传感器做很多相同的工作,但是提供不同编程接口。
Acme O2 Sensor Proxy提供两个服务:
getO2Conc():返回0~100范围无符号整数的氧气浓度getO2Flow():返回氧气流量为一个100 * cc/sec的整数
Ultimate O2 sensor有两个相似的功能:
accessO2Conc():返回范围是0.000~1.000的双精度浮点数(3个有效位)的浓度值accessGasFlow():返回以升/小时为单位的双精度浮点数的总气流量(氧气只是其中一部分)
每个硬件代理需要使用它自己的适配器来转化为期望的客户接口。
// AcmeO2Adapter.c Acme氧气适配器实现// 该适配器将Acme传感器的接口转换为客户期望的接口
int AcmeO2Adapter_gimmeO2Conc(AcmeO2Adapter* const me) { // 直接调用Acme传感器代理的getO2Conc方法 // 返回值已经是0-100的整数,无需转换 return me->itsAcmeO2SensorProxy->getO2Conc();}
int AcmeO2Adapter_gimmeO2Flow(AcmeO2Adapter* const me) { // 调用Acme传感器代理的getO2Flow方法 // 原始数据是100*cc/sec,需要转换为cc/min // 转换公式:(100*cc/sec) * 60 / 100 = cc/min return (me->itsAcmeO2SensorProxy->getO2Flow() * 60) / 100;}// UltimateO2Adapter.c Ultimate氧气适配器实现// 该适配器将Ultimate传感器的接口转换为客户期望的接口
int UltimateO2Adapter_gimmeO2Conc(UltimateO2Adapter* const me) { // 调用Ultimate传感器代理的accessO2Conc方法 // 原始数据是0.000-1.000的浮点数,需要转换为0-100的整数 // 转换公式:浮点数 * 100 = 百分比整数 return (int)(me->itsUltimateO2SensorProxy ->accessO2Conc() * 100);}
int UltimateO2Adapter_gimmeO2Flow(UltimateO2Adapter* const me) { double totalFlow;
// 从传感器获取总气流量(升/小时) totalFlow = me->itsUltimateO2SensorProxy->accessGasFlow() * 1000.0 / 60.0; // 转换公式:升/小时 转为 cc/min // 1升 = 1000cc,1小时 = 60分钟 // 所以:升/小时 * 1000 / 60 = cc/min
// 现在返回氧气流量部分 // 总流量乘以氧气浓度得到氧气流量 // 并返回为整数 return (int)(totalFlow * me->itsUltimateO2SensorProxy->accessO2Conc());}硬件适配器 = 接口翻译机,让“不同方言”的硬件都说同一种“普通话”,客户代码再也不用学外语。
1️⃣ 没有适配器 = 麻烦
客户代码 ─┬─ 直接调用 Acme 的 getO2Conc() └─ 直接调用 Ultimate 的 accessO2Conc()换一家传感器 → 客户代码全部重写。
2️⃣ 有了适配器 = 一句话
客户 → iO2Sensor.gimmeO2Conc() → AcmeO2Adapter → Acme 传感器客户 → iO2Sensor.gimmeO2Conc() → UltimateO2Adapter → Ultimate 传感器客户永远只认识 iO2Sensor,换哪家硬件都零改动。
3️⃣ 适配器内部 = 只做翻译
AcmeO2Adapter { gimmeO2Conc() { return proxy.getO2Conc(); } // 无需转换 gimmeO2Flow() { return proxy.getO2Flow()*60/100; } // 单位换算}
UltimateO2Adapter { gimmeO2Conc() { return (int)(proxy.accessO2Conc()*100); } // 0-1 → 0-100 gimmeO2Flow() { return (int)(proxy.accessGasFlow()*1000/60*proxy.accessO2Conc()); }}关键要点总结
-
硬件适配器模式的核心价值:
- 允许不同硬件接口的统一访问
- 保护客户代码不受硬件更换的影响
- 提高硬件代理的可重用性
-
实现要点:
- 适配器实现客户期望的接口
- 内部调用实际硬件代理的方法
- 负责数据格式转换和单位换算
-
实例中的转换逻辑:
- Acme传感器:流量从100*cc/sec转为cc/min
- Ultimate传感器:浓度从0-1.0转为0-100,流量从升/小时转为cc/min
- 展示了适配器如何处理不同的数据格式和单位
中介者模式(Mediator Pattern)
跳转到“中介者模式(Mediator Pattern)”中介者模式提供在一组元素中复杂交互协调的一种方法。 中介者 = 乐队指挥; 乐器 = 舵机/推反轮。 乐手只看指挥棒,观众只听整首曲子,没人关心小号手换了谁。 把“中介者模式”再拆成 4 句顺口溜:
-
多设备别直连 7 个舵机如果互相喊话,连线会爆炸;中介者把它们全拉到一个群里,只准跟群主说话。
-
群主发号施令 你只需要跟
RobotArmManager说一句“去(10,20,30)抓”,它内部算好 100 步轨迹,然后逐一把命令私聊给每个舵机。 -
改设备不动客户 换舵机型号、加减速曲线、换抓取顺序,都只改群主,客户代码一行不动。
-
代码就三步
RobotArmManager mgr;mgr.addJoint(&j1); // 把设备拉进群mgr.graspAt(x,y,z,time); // 一句话完成协作
抽象:当使用元素的行为必须按照有明确定义且复杂的方式协调时,中介者模式管理不同硬件元素特别有用。这对于C应用特别有用,因为它不需要很多客户化(子类化),能将复杂性放到实现中。
问题:很多嵌入式应用控制几组联动器,它们必须合作来达到预期效果。例如,为达到多关节机器人手臂协同运动,所有的马达必须共同工作来提供期望的手臂运动。相似的,使用反作用轮或者航天器中的三维推进器也需要很多不同的这类设备,在正确的时间和使用恰到好处的力以达到姿态稳定。
模式结构:
效果:该模式创建中介者来协调合作的动态器集合,但是不需要直接耦合这些设备。这通过最少化耦合点并在单个元素内封装协作模式大幅简化了”实体化”。每当合作者想让接装另一个合作者,它只需要通知能够决定如何以集体协作的整体响应的中介者。由于很多嵌入式系统必须以高精确时间约束响应,动作间的延时可能导致数不稳定或不良影响。
示例:
在机器人系统的实例中,Robot Arm Manager收到指定的请求空间(x、y、z)和时间(t)上指定点来抓取物体。它首先通过computeTrajectory()函数计算手臂运动轨迹,并且输出一组nSteps行动(最多100),每个行动由7个问题系统的一组命令组成。如果要达到一个目标,则Robot Arm Manager调用executeStep()函数nSteps次来执行计算过的行动序列。每运行一步,一些命令会送回相设备(非零),这会导致函数计算下一步错误,且该函数会有效续运行动器的移动序列。


#include "GraspingManipulator.h"#include "RotatingArmJoint.h"#include "SlidingArmJoint.h"#include "Action.h"
/* RobotArmManager类定义 */typedef struct RobotArmManager RobotArmManager;
struct RobotArmManager { /* 当前步骤 */ unsigned int currentStep;
/* 总步骤数 */ unsigned int nSteps;
/* 抓取机械手指针 - 具体协作者1 */ struct GraspingManipulator* itsGraspingManipulator;
/* 旋转关节数组 - 具体协作者2(4个关节) */ struct RotatingArmJoint* itsRotatingArmJoint[4];
/* 滑动关节数组 - 具体协作者3(2个关节) */ struct SlidingArmJoint* itsSlidingArmJoint[2];
/* 动作序列数组(最多100个动作) */ struct Action* itsAction[100];};
/* 构造函数和析构函数 */void RobotArmManager_Init(RobotArmManager* const me);void RobotArmManager_Cleanup(RobotArmManager* const me);
/* 操作函数 *//* 计算轨迹:根据目标位置(x,y,z)和时间t计算运动轨迹 */void RobotArmManager_computeTrajectory(RobotArmManager* const me, int x, int y, int z, int t);
/* 执行单步:执行当前步骤的动作 */int RobotArmManager_executeStep(RobotArmManager* const me);
/* 抓取操作:执行抓取动作序列 */int RobotArmManager_graspAt(RobotArmManager* const me, int x, int y, int z, int t);
/* 归零操作:将所有关节恢复到初始位置 */int RobotArmManager_zero(RobotArmManager* const me);
/* 抓取机械手的设置和获取函数 */struct GraspingManipulator* RobotArmManager_getItsGraspingManipulator(const RobotArmManager* const me);void RobotArmManager_setItsGraspingManipulator(RobotArmManager* const me, struct GraspingManipulator* p_GraspingManipulator);
/* 旋转关节的管理函数 */int RobotArmManager_getItsRotatingArmJoint(const RobotArmManager* const me);void RobotArmManager_addItsRotatingArmJoint(RobotArmManager* const me, struct RotatingArmJoint* p_RotatingArmJoint);void RobotArmManager_removeItsRotatingArmJoint(RobotArmManager* const me, struct RotatingArmJoint* p_RotatingArmJoint);void RobotArmManager_clearItsRotatingArmJoint(RobotArmManager* const me);
/* 滑动关节的管理函数 */int RobotArmManager_getItsSlidingArmJoint(const RobotArmManager* const me);void RobotArmManager_addItsSlidingArmJoint(RobotArmManager* const me, struct SlidingArmJoint* p_SlidingArmJoint);void RobotArmManager_removeItsSlidingArmJoint(RobotArmManager* const me, struct SlidingArmJoint* p_SlidingArmJoint);void RobotArmManager_clearItsSlidingArmJoint(RobotArmManager* const me);
/* 动作序列的管理函数 */void RobotArmManager_addItsAction(RobotArmManager* const me, struct Action* p_Action);void RobotArmManager_removeItsAction(RobotArmManager* const me, struct Action* p_Action);void RobotArmManager_clearItsAction(RobotArmManager* const me);int RobotArmManager_getItsAction(const RobotArmManager* const me);
/* 创建和销毁函数 */RobotArmManager* RobotArmManager_Create(void);void RobotArmManager_Destroy(RobotArmManager* const me);
#endif// RobotArmManager.c(核心实现)#include "RobotArmManager.h"
/* 清理关联关系的静态辅助函数 */static void cleanUpRelations(RobotArmManager* const me);
/* 初始化函数:设置初始状态 */void RobotArmManager_Init(RobotArmManager* const me) { int pos;
/* 初始化所有旋转关节指针为NULL(4个关节) */ for(pos = 0; pos < 100; ++pos) { me->itsAction[pos] = NULL; }
/* 初始化抓取机械手指针为NULL */ me->itsGraspingManipulator = NULL;
/* 初始化所有旋转关节指针为NULL(4个关节) */ for(pos = 0; pos < 4; ++pos) { me->itsRotatingArmJoint[pos] = NULL; }
/* 初始化所有滑动关节指针为NULL(2个关节) */ for(pos = 0; pos < 2; ++pos) { me->itsSlidingArmJoint[pos] = NULL; }}
/* 清理函数 */void RobotArmManager_Cleanup(RobotArmManager* const me) { cleanUpRelations(me);}
/* computeTrajectory操作 * 该函数根据目标位置(x,y,z,t)计算机械臂的运动轨迹 * 生成一系列动作(最多100个),每个动作包含给各个关节的命令 * 这是一个复杂的计算过程,这里仅提供占位实现 */void RobotArmManager_computeTrajectory(RobotArmManager* const me, int x, int y, int z, int t) {
Action* ap; int j;
/* 初始化步骤数为0 */ me->nSteps = 0;
/* 清除所有现有动作 */ RobotArmManager_clearItsAction(me);
/* 移动机械臂到机械手打开的位置 */ ap = Action_Create(); RobotArmManager_addItsAction(me, ap); ap->rotatingArmJoint1=1; ap->rotatingArmJoint2=2; ap->rotatingArmJoint3=3; ap->rotatingArmJoint4=4; ap->slidingArmJoint1=10; ap->slidingArmJoint2=20; ap->manipulatorForce=0; ap->manipulatorOpen=1;
/* 抓取物体 */ ap = Action_Create(); RobotArmManager_addItsAction(me, ap); ap->rotatingArmJoint1=1; ap->rotatingArmJoint2=2; ap->rotatingArmJoint3=3; ap->rotatingArmJoint4=4; ap->slidingArmJoint1=10; ap->slidingArmJoint2=20; ap->manipulatorForce=10; ap->manipulatorOpen=0;
/* 返回零位置 */ ap = Action_Create(); RobotArmManager_addItsAction(me, ap); ap->rotatingArmJoint1=0; ap->rotatingArmJoint2=0; ap->rotatingArmJoint3=0; ap->rotatingArmJoint4=0; ap->slidingArmJoint1=0; ap->slidingArmJoint2=0; ap->manipulatorForce=10; ap->manipulatorOpen=0;
/* 设置总步骤数为3 */ me->nSteps = 3;}
/* executeStep操作 * 执行动作链中的单个步骤 * 通过执行当前动作中的所有命令来完成 */int RobotArmManager_executeStep(RobotArmManager* const me) { int actionValue = 0; int step = me->currentStep; int status = 0;
/* 检查是否还有步骤需要执行 */ if (me->itsAction[step]) { /* 旋转关节1的控制 */ actionValue = me->itsAction[step]->rotatingArmJoint1; status = RotatingArmJoint_rotate(me->itsRotatingArmJoint[0], actionValue); if (status) return status;
/* 旋转关节2的控制 */ actionValue = me->itsAction[step]->rotatingArmJoint2; status = RotatingArmJoint_rotate(me->itsRotatingArmJoint[1], actionValue); if (status) return status;
/* 旋转关节3的控制 */ actionValue = me->itsAction[step]->rotatingArmJoint3; status = RotatingArmJoint_rotate(me->itsRotatingArmJoint[2], actionValue); if (status) return status;
/* 旋转关节4的控制 */ actionValue = me->itsAction[step]->rotatingArmJoint4; status = RotatingArmJoint_rotate(me->itsRotatingArmJoint[3], actionValue); if (status) return status;
/* 滑动关节1的控制 */ actionValue = me->itsAction[step]->slidingArmJoint1; status = SlidingArmJoint_setLength(me->itsSlidingArmJoint[0], actionValue); if (status) return status;
/* 滑动关节2的控制 */ actionValue = me->itsAction[step]->slidingArmJoint2; status = SlidingArmJoint_setLength(me->itsSlidingArmJoint[1], actionValue); if (status) return status;
/* 机械手力度控制 */ actionValue = me->itsAction[step]->manipulatorForce; status = GraspingManipulator_setMaxForce(me->itsGraspingManipulator, actionValue); if (status) return status;
/* 机械手开合控制 */ if (me->itsAction[step]->manipulatorOpen) status = GraspingManipulator_open(me->itsGraspingManipulator); else status = GraspingManipulator_close(me->itsGraspingManipulator); }
return status;}
/* graspAt操作:客户端调用的主要函数 * 该操作执行: * 1. 将伺服归零 * 2. 用computeTrajectory()计算轨迹 * 3. 执行构建的动作列表中的每个步骤 */int RobotArmManager_graspAt(RobotArmManager* const me, int x, int y, int z, int t) {
/* 设置当前步骤为-1(未开始) */ me->currentStep = -1; me->nSteps = 0;
/* 归零所有关节 */ RobotArmManager_zero(me);
/* 计算运动轨迹 */ RobotArmManager_computeTrajectory(me, x, y, z, t);
/* 如果有步骤需要执行 */ if (me->nSteps == 0) { me->status = -1; } else { /* 执行所有步骤 */ do { me->currentStep++; me->status = RobotArmManager_executeStep(me); } while (me->status == 0 && me->currentStep < me->nSteps); }
return me->status;}
/* zero操作 * 将所有伺服恢复到起始默认位置 */int RobotArmManager_zero(RobotArmManager* const me) { /* 归零所有设备 */ int j;
/* 归零所有旋转关节(4个) */ for (j=0; j<4; j++) { if (me->itsRotatingArmJoint[j] == NULL) return -1; if (RotatingArmJoint_zero(me->itsRotatingArmJoint[j])) return -1; }
/* 归零所有滑动关节(2个) */ for (j=0; j<2; j++) { if (me->itsSlidingArmJoint[j] == NULL) return -1; if (SlidingArmJoint_zero(me->itsSlidingArmJoint[j])) return -1; }
/* 归零抓取机械手 */ if (me->itsGraspingManipulator == NULL) return -1; if (GraspingManipulator_open(me->itsGraspingManipulator)) return -1;
return 0;}
/* 以下是各种管理函数的实现... *//* 这些函数用于管理协作者对象的添加、删除和访问 */模式要点总结:
- 中介者模式的核心思想:通过一个中介者对象来封装一组对象之间的交互,使各对象不需要显式地相互引用,从而降低耦合度。
- 在嵌入式系统中的应用:特别适合管理需要协调控制的硬件设备组,如机器人手臂的多个关节需要协同工作。
- 关键实现要点:
- 中介者(RobotArmManager)持有所有协作者的引用
- 协作者通过中介者进行间接通信
- 复杂的协调逻辑封装在中介者内部
- 优势:
- 降低了各组件间的耦合度
- 集中化的控制逻辑易于维护和修改
- 可以独立地改变和复用各个协作者
- 需要注意:
- 在实时系统中要考虑延时影响
- 中介者可能成为复杂性的集中点
观察者模式(Observer Pattern)
跳转到“观察者模式(Observer Pattern)”抽象:观察者模式又称”发布-订阅模式”,适用于一组稳定对象间的相关数据同步需求。它需要满足以下条件,
- 需要数据服务器对任何验证信息完全解耦
- 客户需要数据服务器维护任何验证数据能够进行读写
- 数据服务器需要在数据更新时立即通知客户
“你订了公众号,文章一推送你就收到;不用每分钟刷手机,也不用让作者知道你姓甚名谁。” 观察者模式 = “数据一更新,主动推送到家”,省 CPU、省耦合、省代码。 在嵌入式里也一样:
- 公众号 = 数据服务器(温度传感器、GPS 模块……)
- 读者 = 各个客户端(显示器、记录器、报警器……)
- 推送 = 数据一更新,服务器主动“@所有人”
1️⃣ 没有观察者 = 傻轮询
客户端A ──→ 每 100 ms 问一次“几度?”客户端B ──→ 每 100 ms 问一次“几度?”客户端C ──→ 每 100 ms 问一次“几度?”CPU 全在空转,服务器还得应付一堆“在吗?”
2️⃣ 有了观察者 = 微信推送
温度传感器(Subject)├─ 订阅列表 → 客户端A├─ 订阅列表 → 客户端B└─ 订阅列表 → 客户端C数据一变,自动群发,客户端躺着收消息。
3️⃣ 在代码里就 3 步
/* 1. 服务器:有人订阅就记下来 */void tempSensor_subscribe(TempSensor* me, Observer* o){ me->observerList[me->count++] = o;}
/* 2. 服务器:数据变了就群发 */void tempSensor_notify(TempSensor* me, float newTemp){ for(int i=0;i<me->count;i++) me->observerList[i]->update(newTemp);}
/* 3. 客户端:实现update即可 */void display_update(float t){ printf("温度=%.1f\n", t); }问题: 当数据改变时,每个客户端都需要从数据服务器获取新数据。但计算浪费会发生在,
- 客户通过不断轮询来获得新数据(浪费CPU资源)
- 服务器需要知道所有客户机-服务器关系(耦合度高)
模式结构:
观察者模式的核心机制包括以下几个关键角色:
- AbstractSubject(抽象主题):维护订阅者列表的数据服务器
- AbstractClient(抽象客户端):接收数据更新的客户端接口
- ConcreteSubject(具体主题):实现具体的数据发布功能
- ConcreteClient(具体客户端):实现具体的数据接收功能
- Datum(数据):在主题和客户端之间传递的数据载体
- NotificationHandle(通知句柄):用于管理通知机制的辅助类
协作模式:
客户端通过调用subscribe()方法向主题注册,主题将客户端的acceptPtr函数指针保存到订阅者列表中。当数据更新时,主题调用notify()方法遍历所有订阅者并调用它们的accept()方法。
实例: 下面通过一个气体传感器监控系统的例子来展示观察者模式的实现:
/* GasData.h - 气体数据头文件 */#ifndef GasData_H#define GasData_H
/* GasData 结构体定义 * 作为观察者模式中的数据载体(Datum) * 在主题(传感器)和观察者(客户端)之间传递 */typedef struct GasData GasData;struct GasData { /* 气体参数 */ unsigned short N2Conc; // 氮气浓度 unsigned short O2Conc; // 氧气浓度 unsigned int flowRate; // 气体流量};
/* 构造和析构函数 */void GasData_Init(GasData* const me);void GasData_Cleanup(GasData* const me);
/* 工厂方法 */GasData* GasData_Create(void);void GasData_Destroy(GasData* const me);
#endif
/* ============================================= *//* GasData.c - 气体数据实现文件 */#include "GasData.h"
/* 初始化气体数据 * 将所有数值设为0 */void GasData_Init(GasData* const me) { /* 初始化各个字段为默认值 */}
/* 清理函数 * 由于GasData是简单数据结构,无需特殊清理 */void GasData_Cleanup(GasData* const me) { /* 无需清理操作 */}
/* 创建GasData实例 * 动态分配内存并初始化 */GasData* GasData_Create(void) { GasData* me = (GasData*) malloc(sizeof(GasData)); if(me != NULL) { GasData_Init(me); } return me;}
/* 销毁GasData实例 * 清理并释放内存 */void GasData_Destroy(GasData* const me) { if(me != NULL) { GasData_Cleanup(me); } free(me);}
/* ============================================= *//* main.c - 主程序示例 */#include <stdio.h>#include "GasSensor.h"#include "DisplayClient.h"#include "GasData.h"
/* 观察者模式使用示例 * 演示传感器(发布者)和显示客户端(观察者)的协作 */int main() { /* 步骤1:创建传感器(发布者) */ GasSensor* sensor = GasSensor_Create(); printf("=== 气体监控系统启动 ===/n/n");
/* 步骤2:创建多个显示客户端(观察者) */ DisplayClient* display1 = DisplayClient_Create(); DisplayClient* display2 = DisplayClient_Create(); DisplayClient* display3 = DisplayClient_Create();
/* 步骤3:建立关联关系 * 每个客户端都需要知道它要观察的传感器 */ DisplayClient_setItsGasSensor(display1, sensor); DisplayClient_setItsGasSensor(display2, sensor); DisplayClient_setItsGasSensor(display3, sensor);
/* 步骤4:注册观察者 * 每个客户端向传感器注册自己 * 这样传感器就知道要通知哪些客户端 */ printf("注册观察者.../n"); DisplayClient_register(display1); DisplayClient_register(display2); DisplayClient_register(display3); printf("已注册3个显示客户端/n/n");
/* 步骤5:模拟传感器数据更新 */ printf("=== 第1次数据更新 ===/n"); /* 当传感器获得新数据时,会自动通知所有注册的观察者 */ GasSensor_newData(sensor, 100, /* 流量: 100 */ 78, /* N2浓度: 78% */ 21); /* O2浓度: 21% */
printf("/n=== 第2次数据更新 ===/n"); GasSensor_newData(sensor, 150, /* 流量: 150 */ 80, /* N2浓度: 80% */ 19); /* O2浓度: 19% */
/* 步骤6:动态管理观察者 */ printf("/n=== 取消一个观察者的订阅 ===/n"); /* 这里应该保存acceptPtr以便取消订阅 */ /* GasSensor_unsubscribe(sensor, acceptPtr); */
printf("/n=== 第3次数据更新 ===/n"); GasSensor_newData(sensor, 200, /* 流量: 200 */ 85, /* N2浓度: 85% */ 15); /* O2浓度: 15% - 可能触发低氧警报 */
/* 步骤7:清理资源 */ printf("/n=== 系统关闭 ===/n"); DisplayClient_Destroy(display1); DisplayClient_Destroy(display2); DisplayClient_Destroy(display3); GasSensor_Destroy(sensor);
return 0;}
/* ============================================= *//* 扩展示例:其他类型的观察者 */
/* SafetyMonitorClient - 安全监控客户端 * 另一种类型的观察者,专注于安全检查 */typedef struct SafetyMonitorClient { struct GasData* itsGasData; struct GasSensor* itsGasSensor; int alarmTriggered; // 警报状态} SafetyMonitorClient;
/* 安全监控客户端的accept实现 * 检查气体浓度是否在安全范围内 */void SafetyMonitorClient_accept(SafetyMonitorClient* const me, struct GasData* g) { if (!me->itsGasData) { me->itsGasData = GasData_Create(); }
/* 复制数据 */ me->itsGasData->flowRate = g->flowRate; me->itsGasData->N2Conc = g->N2Conc; me->itsGasData->O2Conc = g->O2Conc;
/* 安全检查逻辑 */ if (g->O2Conc < 18) { printf("[安全警报] 氧气浓度过低: %d%%/n", g->O2Conc); me->alarmTriggered = 1; } else if (g->O2Conc > 23) { printf("[安全警报] 氧气浓度过高: %d%%/n", g->O2Conc); me->alarmTriggered = 1; } else { me->alarmTriggered = 0; printf("[安全监控] 气体浓度正常/n"); }}
/* DataLoggerClient - 数据记录客户端 * 将所有数据变化记录到文件 */typedef struct DataLoggerClient { struct GasData* itsGasData; struct GasSensor* itsGasSensor; FILE* logFile;} DataLoggerClient;
void DataLoggerClient_accept(DataLoggerClient* const me, struct GasData* g) { /* 记录到日志文件 */ if (me->logFile) { fprintf(me->logFile, "时间戳: %ld, 流量: %d, N2: %d%%, O2: %d%%/n", time(NULL), g->flowRate, g->N2Conc, g->O2Conc); fflush(me->logFile); }}观察者模式通过以下关键机制实现了发布者和订阅者的解耦:
-
函数指针回调机制
- 使用
gasDataAcceptorPtr类型定义回调函数 - 第一个参数是订阅者实例指针,第二个参数是数据指针
- 这种设计允许任何类型的对象成为观察者
- 使用
-
订阅者管理
- 使用固定大小数组(100个元素)存储订阅者
- 每个订阅者用
GasNotificationHandle结构体表示 - 包含实例指针和回调函数指针
通知流程
新数据到达 → newData() → notify() → 遍历订阅者列表 → 调用每个accept()通知实现
// 遍历所有订阅者并调用其回调函数for (pos = 0; pos < MAX_SUBSCRIBERS; ++pos) { if (订阅者存在) { 订阅者->acceptorPtr(订阅者->instancePtr, 新数据); }}客户端注册
// 客户端注册,客户端主动向发布者注册GasSensor_subscribe(传感器, 自己的指针, &自己的accept函数);应用场景
观察者模式特别适合以下场景:
- 实时数据监控:如本例的气体传感器系统
- 事件驱动系统:GUI事件处理、消息队列
- 模型-视图架构:MVC中的Model和View关系
- 分布式事件处理:微服务间的事件通知
注意事项
- 内存管理:确保正确管理动态分配的通知句柄
- 循环引用:避免观察者和主题之间的循环引用
- 通知顺序:考虑是否需要保证通知顺序
- 性能优化:大量观察者时考虑使用链表替代数组
- 线程安全:多线程环境下需要添加同步机制
去抖动模式
跳转到“去抖动模式”这个模式用于消除来自金属表面间歇性连接引起的多个假事件。当机械式开关(如按钮)被按下或释放时,金属触点会产生”弹性”反弹,在短时间内产生多个导通/断开信号,这种现象称为接触抖动。
为什么需要去抖动?
- 机械开关/按钮在按下或释放瞬间,金属触点会产生多次接触-分离
- 这种”弹跳”现象会在几毫秒内产生多个电平变化
- 如果不处理,系统会误认为用户进行了多次操作
去抖动的基本原理
实际信号: ___╱╲╱╲___________ (有抖动)期望信号: ___╱───────────── (稳定)采样点: ↑ 等待 ↑ 检测变化 确认状态抽象:按钮、拨动开关和机电式继电器都是电子系统的输人设备,它们都有一个共同的问题,即接触金属产生连接,金属变形或“弹性”在开关转换时产生间歇连接。由于这与嵌人式系统(以微秒或更快)的反应速度相比发生得非常缓慢(以毫秒),从而导致控制系统中有多个电子信号。这个模式通过在初始化信号之后等待一段时间将多个信号减少到一个信号,然后检查状态的方法解决这个问题。
问题: 按钮一按,弹簧会哆嗦几下;但软件只认第一次哆嗦,后面 20 ms 内的哆嗦一概当没看见。 去抖动模式 = “防抖拍照”思想的硬件版:连续哆嗦只留第一帧,后面全当噪点扔掉。
1️⃣ 没有去抖 = 一按触发 N 次
按钮实际波形: __| ̄ ̄|__| ̄|__| ̄ ̄|__软件误当成: 按下-松开-按下-松开-按下2️⃣ 有了去抖 = 只认一次
软件只看: __| ̄ ̄ ̄ ̄ ̄ ̄|__事件: ↓第一次变高起延时20 ms后确认3️⃣ 在代码里 = 3 个变量
uint8_t raw; // 当前引脚电平uint8_t stable; // 去抖后的稳定电平uint32_t lastTime; // 上一次变化的时刻模式结构

示例
// ========================================// 微波炉控制系统 - 去抖动模式应用示例// ========================================
#include <stdio.h>#include <stdlib.h>#include <stdbool.h>
// ========================================// Timer.h - 定时器接口// ========================================typedef struct Timer { // 定时器内部状态(实际实现可能包含硬件定时器寄存器等) unsigned int currentDelay;} Timer;
// 延时函数 - 阻塞式延时指定毫秒数void Timer_delay(Timer* timer, unsigned int delayTime) { // 简化实现:使用循环延时 // 实际应用中应使用硬件定时器或操作系统延时 volatile unsigned long count = delayTime * 1000; while(count--) { // 空循环,消耗时间 }}
// ========================================// Button.h - 物理按钮接口// ========================================typedef struct Button { unsigned char deviceState; // 0 = 按下, 1 = 释放 bool backlightOn; // 背光灯状态 struct ButtonDriver* itsButtonDriver; // 关联的驱动} Button;
// 读取按钮当前状态(模拟硬件读取)unsigned char Button_getState(Button* button) { // 在实际应用中,这里会读取GPIO引脚状态 // 模拟:返回当前设备状态 return button->deviceState;}
// 控制按钮背光灯void Button_backlight(Button* button, unsigned char onOff) { button->backlightOn = (onOff != 0); printf("[按钮] 背光灯 %s\n", button->backlightOn ? "开启" : "关闭");}
// 模拟按钮事件(由硬件中断触发)void Button_sendEvent(Button* button) { // 通知关联的ButtonDriver有事件发生 if (button->itsButtonDriver != NULL) { ButtonDriver_eventReceive(button->itsButtonDriver); }}
// ========================================// MicrowaveEmitter.h - 微波发射器接口// ========================================typedef struct MicrowaveEmitter { bool isEmitting; // 发射状态 int power; // 功率级别 (1-10)} MicrowaveEmitter;
// 启动微波发射void MicrowaveEmitter_startEmitting(MicrowaveEmitter* emitter) { emitter->isEmitting = true; printf("[微波发射器] 启动发射 (功率: %d)\n", emitter->power);}
// 停止微波发射void MicrowaveEmitter_stopEmitting(MicrowaveEmitter* emitter) { emitter->isEmitting = false; printf("[微波发射器] 停止发射\n");}
// ========================================// ButtonDriver实现(核心去抖逻辑)// ========================================typedef struct ButtonDriver { unsigned char oldState; // 上一次的稳定状态 unsigned char toggleOn; // 切换状态 Button* itsButton; // 关联的按钮 MicrowaveEmitter* itsMicrowaveEmitter; // 关联的发射器 Timer* itsTimer; // 关联的定时器} ButtonDriver;
// 去抖延时时间(毫秒)#define DEBOUNCE_TIME_MS 40
// 事件接收处理 - 实现去抖逻辑void ButtonDriver_eventReceive(ButtonDriver* driver) { printf("\n[驱动] 检测到按钮事件...\n");
// 步骤1: 延时等待抖动结束 printf("[驱动] 开始去抖延时 %dms\n", DEBOUNCE_TIME_MS); Timer_delay(driver->itsTimer, DEBOUNCE_TIME_MS);
// 步骤2: 延时后重新读取状态 unsigned char currentState = Button_getState(driver->itsButton); printf("[驱动] 延时后读取状态: %s\n", currentState ? "释放" : "按下");
// 步骤3: 比较状态是否真的改变 if (currentState != driver->oldState) { printf("[驱动] 确认状态变化: %s -> %s\n", driver->oldState ? "释放" : "按下", currentState ? "释放" : "按下");
// 更新保存的状态 driver->oldState = currentState;
// 步骤4: 根据新状态执行相应动作 if (currentState == 0) { // 按钮被按下 driver->toggleOn = 1; Button_backlight(driver->itsButton, 1); MicrowaveEmitter_startEmitting(driver->itsMicrowaveEmitter); } else { // 按钮被释放 driver->toggleOn = 0; Button_backlight(driver->itsButton, 0); MicrowaveEmitter_stopEmitting(driver->itsMicrowaveEmitter); } } else { printf("[驱动] 状态未变化,忽略抖动信号\n"); }}
// ========================================// 测试程序 - 模拟按钮操作// ========================================
// 模拟带抖动的按钮按下void simulateButtonPress(Button* button) { printf("\n=== 模拟按钮按下(带抖动)===\n");
// 模拟抖动:快速切换状态多次 button->deviceState = 0; // 按下 Button_sendEvent(button);
// 实际硬件中,这些抖动会在几毫秒内发生 // 但由于去抖延时,只有第一个事件会被处理 button->deviceState = 1; // 抖动(释放) button->deviceState = 0; // 抖动(按下) button->deviceState = 1; // 抖动(释放) button->deviceState = 0; // 最终稳定在按下状态}
// 模拟带抖动的按钮释放void simulateButtonRelease(Button* button) { printf("\n=== 模拟按钮释放(带抖动)===\n");
// 模拟抖动 button->deviceState = 1; // 释放 Button_sendEvent(button);
// 抖动信号(会被忽略) button->deviceState = 0; // 抖动 button->deviceState = 1; // 抖动 button->deviceState = 0; // 抖动 button->deviceState = 1; // 最终稳定在释放状态}
// ========================================// 主程序// ========================================int main() { printf("========================================\n"); printf(" 微波炉去抖动控制系统演示 \n"); printf("========================================\n\n");
// 创建系统组件 Timer timer = {0};
Button startButton = { .deviceState = 1, // 初始状态:释放 .backlightOn = false, .itsButtonDriver = NULL };
MicrowaveEmitter emitter = { .isEmitting = false, .power = 5 // 中等功率 };
ButtonDriver driver = { .oldState = 1, // 初始状态:释放 .toggleOn = 0, .itsButton = &startButton, .itsMicrowaveEmitter = &emitter, .itsTimer = &timer };
// 建立双向关联 startButton.itsButtonDriver = &driver;
printf("系统初始化完成\n"); printf("- 按钮初始状态: 释放\n"); printf("- 微波发射器: 关闭\n"); printf("- 去抖延时设置: %dms\n", DEBOUNCE_TIME_MS);
// 测试场景1:按下按钮(带抖动) printf("\n[测试1] 用户按下启动按钮...\n"); simulateButtonPress(&startButton);
// 模拟等待一段时间 printf("\n[系统] 微波炉正在工作...\n");
// 测试场景2:释放按钮(带抖动) printf("\n[测试2] 用户释放启动按钮...\n"); simulateButtonRelease(&startButton);
// 测试场景3:快速连续按压(测试去抖效果) printf("\n[测试3] 模拟快速连续按压...\n"); for(int i = 0; i < 3; i++) { printf("\n--- 第 %d 次按压 ---\n", i+1); // 快速切换状态 startButton.deviceState = 0; Button_sendEvent(&startButton);
// 立即释放 startButton.deviceState = 1; // 如果没有去抖,这会导致快速开关 // 但有去抖后,只有稳定的状态会被识别 }
printf("\n========================================\n"); printf(" 测试完成 \n"); printf("========================================\n");
return 0;}
// ========================================// 实际硬件环境下的中断处理示例(伪代码)// ========================================/*// GPIO中断服务程序void GPIO_ISR(void) { // 清除中断标志 CLEAR_INTERRUPT_FLAG();
// 禁用该引脚的中断(防止抖动期间重复触发) DISABLE_GPIO_INTERRUPT();
// 发送事件到按钮驱动 Button_sendEvent(&systemButton);
// 在去抖延时后重新使能中断 // (这通常在延时回调中完成)}
// 定时器回调函数(去抖延时结束后)void Timer_Callback(void) { // 读取稳定后的状态 unsigned char stableState = READ_GPIO_PIN();
// 处理状态变化 if (stableState != lastStableState) { // 执行相应动作 ProcessStateChange(stableState); lastStableState = stableState; }
// 重新使能GPIO中断 ENABLE_GPIO_INTERRUPT();}*/中断模式 (Interrupt Pattern)
跳转到“中断模式 (Interrupt Pattern)”抽象:中断模式是一种构造系统的方式,用于对传入事件做出适当的反应。它确实需要一些与处理器和编译器相关的服务,但是大部分嵌入式编译器,甚至是一些操作系统为这个目的提供服务。
**问题 **:
- 事件优先级不等:在很多系统中,事件分为不同等级的紧急度
- 高优先级事件处理:大多数嵌入式系统至少有一些高紧急度的事件,即使在系统非常繁忙地处理其他事件时,也必须处理这些事件
- 轮询模式的局限性:在本章其他内容中讨论的轮询模式中,当系统方便的时候寻找感兴趣的事件
- 实时响应需求:虽然这样是有好处的,能够不中断执行主要的过程,但它的缺点是高紧急度和高频率的事件可能得不到及时处理,或者可能一起丢失
解决方案:中断模式通过立即停止当前的过程,处理传入事件来解决这个问题,并且随后返回原来的计算中。
模式结构

协作角色 InterruptHandler (中断处理器) 职责:中断模式中唯一有行为的元素,它有安装和卸载中断向量的功能,并且本身提供中断服务程序。 关键方法:
install(): 函数以中断目为输入参数,当执行时,它将现有的向量到向量表中,然后使用合适的中断服务程序地址替换它deinstall(): 函数的功能与之相反,用于恢复原有的向量handleInterrupt_x(): 函数处理指定的中断,以中断返回(RTI)语句结束
重要特性:
- 中断服务程序没有参数至关重要,否则当它们试图返回时,将从CPU的栈中弹出错误的值
- 如果编译器提供特殊的interrupt关键字支持,当中断用到时,在函数定义中使用如下关键字
InterruptVectorTable (中断向量表)
作用:是中断服务程序地址的地址数组,它位于触发子处理器的指定内存位置上。
工作机制:
- 当中断x出现时,CPU挂起当前进程,并且间接地通过用在表中相应的第x个索引地址
- 当获得RTI时,CPU恢复执行挂起的计算
vectorPtr (向量指针) 定义:vectorPtr是数据类型,具体是一个返回参数和返回值都的函数指针。
效果:
- 高效响应处理紧迫感事件:中断通过的外理过程(假设没有禁止中断),并且当时紧张的过程正在进行时,慎重使用
- 通常情况优化:当中断服务程序序执行时,关闭中断。这意味着中断服务程序必须快速连行以确保不会丢失其他中断
- 简短高效的ISR:因为中断服务程序必须简短,当使用它们调用其他系统服务时必须非常小心
示例:
; 标准C中的ISR实现; 中断服务程序入口void isr(void) { asm { DI ; disable interrupts (关闭中断) PUSH AF ; save registers (保存寄存器) PUSH BC PUSH DE PUSH HL PUSH IX PUSH IY
/* 在这里放置正常的C代码 */ /* normal C code here */
asm { POP IY ; restore registers (恢复寄存器) POP IX POP HL POP DE POP BC POP AF EI ; enable interrupts (开启中断)
RETI ; return from interrupt (中断返回) } }}// 使用interrupt关键字的简化方式interrupt void isr(void) { /* normal C code here */ /* 正常的C代码放在这里 */}// GCC使用__attribute__规范来表示一个中断句柄void isr(void) __attribute__((interrupt ("IRQ")));void isr(void) { /* normal C code here */ /* 正常的C代码放在这里 */}按钮中断处理实例
- Button硬件设备:按钮是一个中断(索引0),且释放生成另一个(索引1)
- ButtonHandler:为中断它的install()函数指针设置向量的中断处理程序
- LED设备:用于显示按钮状态
// main()int j;Button itsButton;LED itsLED;
// 创建按钮和LED对象itsButton = Button_Create();itsLED = LED_Create();
// 初始化中断向量表for (j=0; j<9; j++) { ISRAddress[j] = NULL; oldVectors[j] = NULL;}
// 设置按钮和LED的关联ButtonHandler_setItsLED(&itsLED);install(); /* 安装中断向量 */
// ButtonHandler.h#ifndef ButtonHandler_H#define ButtonHandler_H
// 函数指针类型定义typedef void (*ButtonVectorPtr)(void);
// LED结构体前向声明struct LED;
// 全局中断向量数组extern ButtonVectorPtr oldVectors[10];
/* 操作函数 */void install(void); // 安装中断向量void deinstall(void); // 卸载中断向量
// 中断处理函数interrupt void handleButtonPushInterrupt(void); // 按钮按下中断处理interrupt void handleButtonReleaseInterrupt(void); // 按钮释放中断处理
// LED操作函数struct LED* ButtonHandler_getItsLED(void); // 获取LED对象void ButtonHandler_setItsLED(struct LED* p_LED); // 设置LED对象
#endif
//ButtonHandler.c#include "ButtonHandler.h"#include "LED.h"#include "RobotInterruptVectorTable.h"
// 全局变量定义ButtonVectorPtr oldVectors[10]; // 保存原始中断向量static struct LED* itsLED; // LED对象指针
// 卸载中断向量,恢复原始状态void deinstall(void) { ISRAddress[0] = oldVectors[0]; // 恢复按钮按下中断向量 ISRAddress[1] = oldVectors[1]; // 恢复按钮释放中断向量}
// 按钮按下中断处理函数interrupt void handleButtonPushInterrupt(void) { LED_LightOn(itsLED); // 按钮按下时点亮LED}
// 按钮释放中断处理函数interrupt void handleButtonReleaseInterrupt(void) { LED_LightOff(itsLED); // 按钮释放时关闭LED}
// 安装中断向量void install(void) { oldVectors[0] = ISRAddress[0]; // 保存原始的按钮按下中断向量 oldVectors[1] = ISRAddress[1]; // 保存原始的按钮释放中断向量
// 安装新的中断处理函数 ISRAddress[0] = handleButtonPushInterrupt; // 按钮按下中断处理 ISRAddress[1] = handleButtonReleaseInterrupt; // 按钮释放中断处理}
// 获取LED对象指针struct LED* ButtonHandler_getItsLED(void) { return (struct LED*)itsLED;}
// 设置LED对象指针void ButtonHandler_setItsLED(struct LED* p_LED) { itsLED = p_LED;}轮询模式 (Polling Pattern)
跳转到“轮询模式 (Polling Pattern)”抽象: 轮询模式是从硬件上检查新数据和信号的最简单方法。轮询能够定期或者不定期进行;定期轮询使用定时器来标识何时应该对硬件采样,而机会轮询是当系统方便的时候轮询,如在主系统功能或在重复执行的周期点之间。机会轮询,顾名思义,缺少规律可循,但是对其他系统从事的活动的及时性影响也小。
就像老师每 5 分钟挨个检查每个同学作业:不管同学有没有写完,老师到点就问一遍,写完就收,没写完就跳过。 1️⃣ 没有轮询 = 靠中断
温度传感器 → 中断 → MCU湿度传感器 → 中断 → MCU光照传感器 → 中断 → MCU中断太多易丢、易冲突;有些老芯片或低速总线压根没中断脚。
2️⃣ 有了轮询 = 老师点名
PeriodicPoller(老师)├─ 5 ms → 问温度 → 有数据就取├─ 5 ms → 问湿度 → 有数据就取└─ 5 ms → 问光照 → 有数据就取时间固定、顺序固定,代码简单、可预期。
3️⃣ 机会轮询 = 课间抽查
系统空闲时 → OpportunisticPoller 再扫一遍问题: 轮询模式解决系统获取传感器数据和硬件信号的问题,当数据或事件不是高度紧急并且数据采样的时间能保证足够短可以用轮询模式。
模式结构:

效果
| 特性 | 轮询模式 | 中断模式 |
|---|---|---|
| 响应速度 | 取决于轮询周期 | 立即响应 |
| CPU占用 | 固定开销 | 仅在事件发生时 |
| 实现复杂度 | 简单 | 较复杂 |
| 适用场景 | 周期性数据采集 | 紧急事件处理 |
适用场景
- 医疗监护设备(如呼吸机监控)
- 工业传感器数据采集
- 环境监测系统
- 不支持中断的硬件设备
设计要点
- 合理设置轮询周期:平衡响应速度和系统负载
- 批量处理:一次轮询中读取所有传感器数据
- 错误处理:考虑传感器故障或数据异常
- 动态调整:根据系统状态调整轮询频率
示例:

#ifndef BCPeriodicPoller_H#define BCPeriodicPoller_H
// 类型定义typedef int deviceData;typedef void (*timerVectorPtr)(void);
// 最大轮询设备数量#define MAX_POLL_DEVICES (10)// 默认轮询时间间隔(毫秒)#define DEFAULT_POLL_TIME (1000)
// 前向声明struct BCTimer;struct BreathingCircuitSensor;struct MedicalDisplay;
// BCPeriodicPoller 类结构定义typedef struct BCPeriodicPoller BCPeriodicPoller;struct BCPeriodicPoller { // 轮询时间间隔 unsigned long pollTime;
// 关联的定时器 struct BCTimer* itsBCTimer;
// 呼吸回路传感器数组(最多3个) struct BreathingCircuitSensor* itsBreathingCircuitSensor[3];
// 医疗显示器 struct MedicalDisplay* itsMedicalDisplay;};
// ==================== 公共接口函数 ====================
// 初始化函数void BCPeriodicPoller_Init(BCPeriodicPoller* const me);
// 清理函数void BCPeriodicPoller_Cleanup(BCPeriodicPoller* const me);
// 操作函数 - 执行轮询void BCPeriodicPoller_poll(BCPeriodicPoller* const me);
// 获取轮询时间void BCPeriodicPoller_getPollTime(BCPeriodicPoller* const me, unsigned long t);
// 开始轮询void BCPeriodicPoller_startPolling(BCPeriodicPoller* const me);
// 停止轮询void BCPeriodicPoller_stopPolling(BCPeriodicPoller* const me);
// ==================== 关联对象管理函数 ====================
// BCTimer 相关struct BCTimer* BCPeriodicPoller_getItsBCTimer(const BCPeriodicPoller* const me);void BCPeriodicPoller_setItsBCTimer(BCPeriodicPoller* const me, struct BCTimer* p_BCTimer);
// BreathingCircuitSensor 相关int BCPeriodicPoller_getItsBreathingCircuitSensor(const BCPeriodicPoller* const me);void BCPeriodicPoller_addItsBreathingCircuitSensor(BCPeriodicPoller* const me, struct BreathingCircuitSensor* p_BreathingCircuitSensor);void BCPeriodicPoller_removeItsBreathingCircuitSensor(BCPeriodicPoller* const me, struct BreathingCircuitSensor* p_BreathingCircuitSensor);void BCPeriodicPoller_clearItsBreathingCircuitSensor(BCPeriodicPoller* const me);
// MedicalDisplay 相关struct MedicalDisplay* BCPeriodicPoller_getItsMedicalDisplay(const BCPeriodicPoller* const me);void BCPeriodicPoller_setItsMedicalDisplay(BCPeriodicPoller* const me, struct MedicalDisplay* p_MedicalDisplay);
// ==================== 生命周期管理函数 ====================
// 创建实例BCPeriodicPoller* BCPeriodicPoller_Create(void);
// 销毁实例void BCPeriodicPoller_Destroy(BCPeriodicPoller* const me);
// 清理关联关系(静态函数)void BCPeriodicPoller_cleanUpRelations(BCPeriodicPoller* const me);
// __setItsBCTimer 内部函数void BCPeriodicPoller___setItsBCTimer(BCPeriodicPoller* const me, struct BCTimer* p_BCTimer);
// __clearItsBCTimer 内部函数void BCPeriodicPoller___clearItsBCTimer(BCPeriodicPoller* const me);
#endif // BCPeriodicPoller_H
// ================================================================// BCPeriodicPoller.c#include "BCPeriodicPoller.h"#include "BCTimer.h"#include "BreathingCircuitSensor.h"#include "MedicalDisplay.h"
// 静态函数声明static void cleanUpRelations(BCPeriodicPoller* const me);
/** * 初始化 BCPeriodicPoller 实例 * @param me 指向 BCPeriodicPoller 实例的指针 */void BCPeriodicPoller_Init(BCPeriodicPoller* const me) { // 设置默认轮询时间 me->pollTime = DEFAULT_POLL_TIME;
// 初始化 BCTimer 为 NULL me->itsBCTimer = NULL;
// 初始化传感器数组 int pos; for(pos = 0; pos < 3; ++pos) { me->itsBreathingCircuitSensor[pos] = NULL; }
// 初始化医疗显示器 me->itsMedicalDisplay = NULL;
// 安装中断处理器(当创建 BCPeriodicPoller 时调用) BCTimer_installInterruptHandler(me->itsBCTimer);
// 设置默认轮询时间 me->pollTime = DEFAULT_POLL_TIME;}
/** * 清理 BCPeriodicPoller 实例 * @param me 指向 BCPeriodicPoller 实例的指针 */void BCPeriodicPoller_Cleanup(BCPeriodicPoller* const me) { // 停止定时器 BCTimer_stopTimer(me->itsBCTimer);
// 移除中断处理器 BCTimer_removeInterruptHandler(me->itsBCTimer);
// 清理所有关联关系 cleanUpRelations(me);}
/** * 执行轮询操作 * 轮询3个呼吸回路传感器并更新医疗显示器 * @param me 指向 BCPeriodicPoller 实例的指针 */void BCPeriodicPoller_poll(BCPeriodicPoller* const me) { int state, data;
// 轮询第一个传感器(氧气浓度) data = BreathingCircuitSensor_getData(me->itsBreathingCircuitSensor[0]); MedicalDisplay_showO2Concentration(me->itsMedicalDisplay, data);
// 轮询第二个传感器(气体流量) data = BreathingCircuitSensor_getData(me->itsBreathingCircuitSensor[1]); state = BreathingCircuitSensor_getState(me->itsBreathingCircuitSensor[1]); MedicalDisplay_showGasFlow(me->itsMedicalDisplay, data); MedicalDisplay_showGasFlowStatus(me->itsMedicalDisplay, state);
// 轮询第三个传感器(回路压力) data = BreathingCircuitSensor_getData(me->itsBreathingCircuitSensor[2]); MedicalDisplay_showCircuitPressure(me->itsMedicalDisplay, data);}
/** * 获取轮询时间间隔 * @param me 指向 BCPeriodicPoller 实例的指针 * @param t 接收轮询时间的变量 */void BCPeriodicPoller_getPollTime(BCPeriodicPoller* const me, unsigned long t) { me->pollTime = t;}
/** * 开始轮询 * 启动定时器,定期执行轮询操作 * @param me 指向 BCPeriodicPoller 实例的指针 */void BCPeriodicPoller_startPolling(BCPeriodicPoller* const me) { // 使用设置的轮询时间间隔启动定时器 BCTimer_startTimer(me->itsBCTimer, me->pollTime);}
/** * 停止轮询 * @param me 指向 BCPeriodicPoller 实例的指针 */void BCPeriodicPoller_stopPolling(BCPeriodicPoller* const me) { BCTimer_stopTimer(me->itsBCTimer);}
/** * 获取关联的 BCTimer 实例 * @param me 指向 BCPeriodicPoller 实例的指针 * @return 返回关联的 BCTimer 指针 */struct BCTimer* BCPeriodicPoller_getItsBCTimer(const BCPeriodicPoller* const me) { return (struct BCTimer*)me->itsBCTimer;}
/** * 设置关联的 BCTimer 实例 * @param me 指向 BCPeriodicPoller 实例的指针 * @param p_BCTimer 要关联的 BCTimer 指针 */void BCPeriodicPoller_setItsBCTimer(BCPeriodicPoller* const me, struct BCTimer* p_BCTimer) { if(p_BCTimer != NULL) { BCTimer__setItsBCPeriodicPoller(p_BCTimer, me); } BCPeriodicPoller___setItsBCTimer(me, p_BCTimer);}
/** * 获取呼吸回路传感器迭代器 * @param me 指向 BCPeriodicPoller 实例的指针 * @return 返回迭代器位置(0表示开始) */int BCPeriodicPoller_getItsBreathingCircuitSensor(const BCPeriodicPoller* const me) { int iter = 0; return iter;}
/** * 添加呼吸回路传感器 * @param me 指向 BCPeriodicPoller 实例的指针 * @param p_BreathingCircuitSensor 要添加的传感器指针 */void BCPeriodicPoller_addItsBreathingCircuitSensor(BCPeriodicPoller* const me, struct BreathingCircuitSensor* p_BreathingCircuitSensor) { int pos; // 查找空位置并添加传感器 for(pos = 0; pos < 3; ++pos) { if(me->itsBreathingCircuitSensor[pos] == NULL) { me->itsBreathingCircuitSensor[pos] = p_BreathingCircuitSensor; break; } }}
/** * 移除指定的呼吸回路传感器 * @param me 指向 BCPeriodicPoller 实例的指针 * @param p_BreathingCircuitSensor 要移除的传感器指针 */void BCPeriodicPoller_removeItsBreathingCircuitSensor(BCPeriodicPoller* const me, struct BreathingCircuitSensor* p_BreathingCircuitSensor) { int pos; // 查找并移除指定的传感器 for(pos = 0; pos < 3; ++pos) { if(me->itsBreathingCircuitSensor[pos] == p_BreathingCircuitSensor) { me->itsBreathingCircuitSensor[pos] = NULL; } }}
/** * 清除所有呼吸回路传感器 * @param me 指向 BCPeriodicPoller 实例的指针 */void BCPeriodicPoller_clearItsBreathingCircuitSensor(BCPeriodicPoller* const me) { int pos; // 清除所有传感器引用 for(pos = 0; pos < 3; ++pos) { me->itsBreathingCircuitSensor[pos] = NULL; }}
/** * 获取关联的医疗显示器 * @param me 指向 BCPeriodicPoller 实例的指针 * @return 返回关联的 MedicalDisplay 指针 */struct MedicalDisplay* BCPeriodicPoller_getItsMedicalDisplay( const BCPeriodicPoller* const me) { return (struct MedicalDisplay*)me->itsMedicalDisplay;}
/** * 设置关联的医疗显示器 * @param me 指向 BCPeriodicPoller 实例的指针 * @param p_MedicalDisplay 要关联的医疗显示器指针 */void BCPeriodicPoller_setItsMedicalDisplay(BCPeriodicPoller* const me, struct MedicalDisplay* p_MedicalDisplay) { me->itsMedicalDisplay = p_MedicalDisplay;}
/** * 创建 BCPeriodicPoller 实例 * @return 返回新创建的实例指针,失败返回 NULL */BCPeriodicPoller* BCPeriodicPoller_Create(void) { // 分配内存 BCPeriodicPoller* me = (BCPeriodicPoller*)malloc(sizeof(BCPeriodicPoller));
if(me != NULL) { // 初始化实例 BCPeriodicPoller_Init(me); }
return me;}
/** * 销毁 BCPeriodicPoller 实例 * @param me 要销毁的实例指针 */void BCPeriodicPoller_Destroy(BCPeriodicPoller* const me) { if(me != NULL) { // 执行清理 BCPeriodicPoller_Cleanup(me);
// 释放内存 free(me); }}
/** * 清理所有关联关系(静态内部函数) * @param me 指向 BCPeriodicPoller 实例的指针 */static void cleanUpRelations(BCPeriodicPoller* const me) { if(me->itsBCTimer != NULL) { // 获取并清理 BCTimer 关联 struct BCPeriodicPoller* p_BCPeriodicPoller = BCTimer_getItsBCPeriodicPoller(me->itsBCTimer);
if(p_BCPeriodicPoller != NULL) { BCTimer__setItsBCPeriodicPoller(me->itsBCTimer, NULL); }
me->itsBCTimer = NULL; }
if(me->itsMedicalDisplay != NULL) { me->itsMedicalDisplay = NULL; }}
/** * 内部函数:设置 BCTimer(带双向关联) * @param me 指向 BCPeriodicPoller 实例的指针 * @param p_BCTimer 要设置的 BCTimer 指针 */void BCPeriodicPoller___setItsBCTimer(BCPeriodicPoller* const me, struct BCTimer* p_BCTimer) { me->itsBCTimer = p_BCTimer;}
/** * 内部函数:清除 BCTimer 关联 * @param me 指向 BCPeriodicPoller 实例的指针 */void BCPeriodicPoller___clearItsBCTimer(BCPeriodicPoller* const me) { me->itsBCTimer = NULL;}状态机的设计模式
跳转到“状态机的设计模式”行为可以定义为随时间变化条件或值的改变。在状态机设计中,行为分为两种:
- 对象或系统历史无关的行为 - 例如
cos(π/4)返回固定结果 - 与历史相关的行为 - 例如移动平均数字滤波器的计算
基本模式分类
- 单事件接收器模式 - 一个事件对应一个接收器实现
- 多事件接收器模式 - 多个事件共享接收器实现
- 状态表模式 - 用表驱动的方式实现状态机
- 状态设计模式 - 用继承和多态实现状态机
- 分解与状态模式 - 将复杂状态分解为AND和OR组合
有限状态机(FSM)的三个基本元素
- 状态(State) - 系统在某个时刻的条件
- 转换(Transition) - 状态之间的切换
- 动作(Action) - 状态转换时执行的操作
OR状态
在单纯的状态机中,元素必须始终正好在它的某个状态中。这种状态关系称为OR状态, 因为元素或者在这个状态,或者在那个状态,但不能同时在多个状态。

- 系统在任一时刻只能处于一个状态
- 状态之间通过事件触发转换
- 每个状态可以有进入/退出动作
与状态
与状态允许一个独立的状态拥有多个正交(独立)的状态区域。系统可以同时处于多个并行的子状态中。
关键要点总结
- 状态机基本要素:状态、转换、动作构成了状态机的核心
- OR状态 vs AND状态:OR状态互斥,AND状态可并存
- 行为分类:进入动作、持续活动、退出动作
- 事件驱动:状态转换由事件触发,可附带条件判断
- 层次化设计:支持嵌套状态和复合状态
// 微波炉状态机示例// 状态转换表表示:表 5-1 状态转换表 Initial \ eventOn \ timeCode \ doorOpen \ doorClose \ tm(timeout)
/* * 状态转换表说明: * * 状态列表: * - ROOT (根状态) * - Off (关闭) * - On (开启) * - Ready (就绪) * - Microwaving (加热中) * - DoorOpen (门开) * - Paused (暂停) * * 事件列表: * - eventOn: 开机事件 * - timeCode: 设置时间 * - doorOpen: 开门 * - doorClose: 关门 * - tm(timeout): 超时 */
// ==================== 状态转换表 ====================/*┌─────────────┬──────────┬───────────┬───────────┬────────────┬─────────────┐│ 当前状态 │ eventOn │ timeCode │ doorOpen │ doorClose │ tm(timeout) │├─────────────┼──────────┼───────────┼───────────┼────────────┼─────────────┤│ ROOT │ → Off │ │ │ │ │├─────────────┼──────────┼───────────┼───────────┼────────────┼─────────────┤│ Off │ │ → Ready │ │ │ │├─────────────┼──────────┼───────────┼───────────┼────────────┼─────────────┤│ On │ → Ready │ │ │ │ │├─────────────┼──────────┼───────────┼───────────┼────────────┼─────────────┤│ Ready │ │→Microwaving│ │ │ → Ready │├─────────────┼──────────┼───────────┼───────────┼────────────┼─────────────┤│ Microwaving │ │ │ →DoorOpen │ │ → Ready │├─────────────┼──────────┼───────────┼───────────┼────────────┼─────────────┤│ DoorOpen │ │ │ │→Microwaving│ │├─────────────┼──────────┼───────────┼───────────┼────────────┼─────────────┤│ Paused │→Microwaving│ │ →DoorOpen │ │ │└─────────────┴──────────┴───────────┴───────────┴────────────┴─────────────┘*/
#include <stdio.h>#include <stdbool.h>#include <stdlib.h>
// ==================== 状态枚举定义 ====================typedef enum { STATE_ROOT, STATE_OFF, STATE_ON, STATE_READY, STATE_MICROWAVING, STATE_DOOR_OPEN, STATE_PAUSED, STATE_MAX} MicrowaveState;
// ==================== 事件枚举定义 ====================typedef enum { EVENT_ON, EVENT_TIME_CODE, EVENT_DOOR_OPEN, EVENT_DOOR_CLOSE, EVENT_TIMEOUT, EVENT_MAX} MicrowaveEvent;
// ==================== 微波炉结构体 ====================typedef struct { MicrowaveState currentState; MicrowaveState parentState; int timeRemaining; // 剩余时间(秒) bool doorIsOpen; // 门的状态 int power; // 功率设置} Microwave;
// ==================== 状态名称(用于调试) ====================const char* stateNames[] = { "ROOT", "Off", "On", "Ready", "Microwaving", "DoorOpen", "Paused"};
const char* eventNames[] = { "eventOn", "timeCode", "doorOpen", "doorClose", "timeout"};
// ==================== 状态动作函数 ====================
// 进入状态时的动作void onEnterState(Microwave* mw, MicrowaveState state) { printf("[ENTRY] 进入状态: %s\n", stateNames[state]);
switch(state) { case STATE_OFF: printf(" -> 微波炉已关闭,功率设为0\n"); mw->power = 0; break;
case STATE_READY: printf(" -> 微波炉就绪,等待输入时间\n"); mw->timeRemaining = 0; break;
case STATE_MICROWAVING: printf(" -> 开始加热,功率设为100%%\n"); mw->power = 100; // 这里应该启动定时器 break;
case STATE_DOOR_OPEN: printf(" -> 门已打开,停止加热\n"); mw->power = 0; mw->doorIsOpen = true; break;
case STATE_PAUSED: printf(" -> 暂停加热,保存剩余时间\n"); mw->power = 0; break;
default: break; }}
// 退出状态时的动作void onExitState(Microwave* mw, MicrowaveState state) { printf("[EXIT] 退出状态: %s\n", stateNames[state]);
switch(state) { case STATE_MICROWAVING: printf(" -> 停止加热\n"); mw->power = 0; break;
case STATE_DOOR_OPEN: printf(" -> 关闭门\n"); mw->doorIsOpen = false; break;
default: break; }}
// ==================== 状态转换逻辑 ====================bool processEvent(Microwave* mw, MicrowaveEvent event) { MicrowaveState oldState = mw->currentState; MicrowaveState newState = oldState; bool transitionOccurred = false;
printf("\n[EVENT] 处理事件: %s (当前状态: %s)\n", eventNames[event], stateNames[oldState]);
// 根据当前状态和事件决定下一个状态 switch(oldState) { case STATE_ROOT: if (event == EVENT_ON) { newState = STATE_OFF; transitionOccurred = true; } break;
case STATE_OFF: if (event == EVENT_TIME_CODE) { newState = STATE_READY; transitionOccurred = true; } break;
case STATE_ON: if (event == EVENT_ON) { newState = STATE_READY; transitionOccurred = true; } break;
case STATE_READY: if (event == EVENT_TIME_CODE) { // 设置了时间,开始加热 mw->timeRemaining = 60; // 假设设置60秒 newState = STATE_MICROWAVING; transitionOccurred = true; } else if (event == EVENT_TIMEOUT) { newState = STATE_READY; transitionOccurred = true; } break;
case STATE_MICROWAVING: if (event == EVENT_DOOR_OPEN) { newState = STATE_DOOR_OPEN; transitionOccurred = true; } else if (event == EVENT_TIMEOUT) { printf(" -> 加热完成!\n"); newState = STATE_READY; transitionOccurred = true; } break;
case STATE_DOOR_OPEN: if (event == EVENT_DOOR_CLOSE) { // 如果还有剩余时间,继续加热 if (mw->timeRemaining > 0) { newState = STATE_MICROWAVING; } else { newState = STATE_READY; } transitionOccurred = true; } break;
case STATE_PAUSED: if (event == EVENT_ON) { newState = STATE_MICROWAVING; transitionOccurred = true; } else if (event == EVENT_DOOR_OPEN) { newState = STATE_DOOR_OPEN; transitionOccurred = true; } break;
default: break; }
// 执行状态转换 if (transitionOccurred && newState != oldState) { onExitState(mw, oldState); mw->currentState = newState; onEnterState(mw, newState); printf("[TRANSITION] %s -> %s\n", stateNames[oldState], stateNames[newState]); } else if (!transitionOccurred) { printf("[INFO] 事件 %s 在状态 %s 下无效\n", eventNames[event], stateNames[oldState]); }
return transitionOccurred;}
// ==================== 模拟定时器 ====================void simulateTimer(Microwave* mw) { if (mw->currentState == STATE_MICROWAVING && mw->timeRemaining > 0) { mw->timeRemaining--; printf("[TIMER] 剩余时间: %d 秒\n", mw->timeRemaining);
if (mw->timeRemaining == 0) { processEvent(mw, EVENT_TIMEOUT); } }}
// ==================== 主程序示例 ====================int main() { Microwave mw = { .currentState = STATE_ROOT, .parentState = STATE_ROOT, .timeRemaining = 0, .doorIsOpen = false, .power = 0 };
printf("=== 微波炉状态机示例 ===\n");
// 模拟一个完整的使用流程 printf("\n1. 初始化微波炉\n"); processEvent(&mw, EVENT_ON); // ROOT -> Off
printf("\n2. 设置时间\n"); processEvent(&mw, EVENT_TIME_CODE); // Off -> Ready
printf("\n3. 再次设置时间开始加热\n"); processEvent(&mw, EVENT_TIME_CODE); // Ready -> Microwaving
printf("\n4. 模拟加热3秒\n"); for(int i = 0; i < 3; i++) { simulateTimer(&mw); }
printf("\n5. 中途开门\n"); processEvent(&mw, EVENT_DOOR_OPEN); // Microwaving -> DoorOpen
printf("\n6. 关门继续加热\n"); processEvent(&mw, EVENT_DOOR_CLOSE); // DoorOpen -> Microwaving
printf("\n7. 继续加热直到完成\n"); while(mw.timeRemaining > 0) { simulateTimer(&mw); }
printf("\n=== 演示结束 ===\n"); printf("最终状态: %s\n", stateNames[mw.currentState]);
return 0;}
/* * 编译运行: * gcc -o microwave microwave.c * ./microwave * * 这个示例展示了: * 1. 完整的状态转换表实现 * 2. 进入/退出动作的处理 * 3. 事件驱动的状态转换 * 4. 层次化状态的概念(虽然简化了) * 5. 定时器事件的处理 */单事件接收器模式
跳转到“单事件接收器模式”抽象 单事件接收器模式依赖于单一事件接收器在客户与状态机间提供接口。在内部,这个单一事件接收器必须接收事件数据类型,不仅识别哪个事件已经发生,并且识别任意伴随事件的数据。该模式能够用在同步状态机(从客户直接接收事件)或者异步状态机(通过中间的事件队列)。
一件事只找一个人办:不管你现在啥状态,这个人当场决定下一步怎么做,省得满世界找人开会。
问题 该模式解决状态机的简单实现问题,适用于同步和异步事件传递。
1️⃣ 没有此模式 = 状态机里到处 if/else
switch(curState){ case IDLE: if(e==BTN_DOWN) ...; break; case RUNNING: if(e==BTN_DOWN) ...; break; case ERROR: if(e==BTN_DOWN) ...; break;}同一个 BTN_DOWN 在所有状态里重复出现,又臭又长。
2️⃣ 有了此模式 = 一件事一个“专员”
Event: BTN_DOWN -> handle_BTN_DOWN(state, data)Event: TIMEOUT -> handle_TIMEOUT(state, data)每个事件对应一个“专员函数”,里面只关心“我现在啥状态,该干啥”,代码集中、易读、易改。
3️⃣ 同步 vs 异步
- 同步:客户直接调专员 → 立即执行
- 异步:客户把事件塞进
EventQueue,专员在后台慢慢处理,线程安全用Mutex锁一下即可。
设计理念:
- 一个事件对应一个接收器
- 接收器内部根据当前状态决定行为
- 状态转换逻辑分散在各个接收器中
核心思想:
- 每个事件类型对应一个处理函数
- 处理函数内部包含所有状态的处理逻辑
- 状态转换逻辑分散在各个事件处理器中
主要问题:
- 代码重复 - 同样的状态检查逻辑可能在多个事件处理器中重复
- 维护困难 - 状态转换逻辑分散,难以获得整体视图
- 扩展性差 - 添加新状态需要修改所有相关的事件处理器
| 组件 | 职责 | 说明 |
|---|---|---|
| Event | 事件载体 | 包含事件类型和数据 |
| EventType | 事件分类 | 定义所有可能的事件类型 |
| EventQueue | 事件缓冲 | 线程安全的事件队列 |
| Mutex | 同步机制 | 保证多线程环境下的数据一致性 |
| StateID | 状态标识 | 记录当前状态 |
| EventDispatcher | 事件分发器 | 核心调度逻辑 |
模式结构
(1)异步事件中单事件接收器状态机的上下文
设计模式要点
- 单一职责:每个类都有明确的职责,Event负责数据传递,Queue负责缓冲,Tokenizer负责业务逻辑
- 解耦设计:通过事件队列解耦事件生产者和消费者
- 线程安全:使用Mutex确保并发环境下的数据一致性
- 状态分层:主状态和子状态的设计提供了更灵活的状态管理
- 核心分发:eventDispatch()方法是整个模式的核心,包含所有状态转换逻辑
(1)同步单事件接收器状态机


示例:
/* * 单事件接收器模式(SERSM)- 计算器分词器示例 * * 这个例子展示了如何用单事件接收器模式实现一个简单的数学表达式分词器。 * 分词器可以识别数字(整数和小数)并进行简单的数学计算。 */
// ==================== 头文件部分 ====================// TSREventQueue.h - 事件队列定义#ifndef TSREVENTQUEUE_H#define TSREVENTQUEUE_H
#include "Mutex.h"
#define QSIZE 100 // 事件队列大小
// 事件类型枚举typedef enum EventType { EVDIGIT, // 数字事件 EVDOT, // 小数点事件 EVWHITESPACE, // 空白字符事件 EVENDOFSTRING // 字符串结束事件} EventType;
// 状态类型枚举typedef enum TSTATETYPE { NULL_STATE, // 空状态 NONUMBER_STATE, // 无数字状态 GOTNUMBER_STATE // 获得数字状态} TSTATETYPE;
// 子状态类型枚举(用于更细粒度的状态管理)typedef enum TSUBSTATETYPE { NULL_SSTATE, // 空子状态 PROCESSINGWHOLEPART_SSTATE, // 处理整数部分 PROCESSINGFRACTIONALPART_SSTATE // 处理小数部分} TSUBSTATETYPE;
// 事件结构体typedef struct { EventType eType; // 事件类型 union eventData { // 事件数据(联合体) char c; // 字符数据 } ed; Event* next; // 指向下一个事件(链表结构)} Event;
// 事件队列结构体typedef struct TSREventQueue { struct TSREventQueue* next; Event queue[QSIZE]; // 事件数组 int size; // 当前队列大小 int head; // 队头索引 int tail; // 队尾索引 struct Mutex* itsMutex; // 互斥锁(用于线程安全)} TSREventQueue;
// ==================== 事件队列操作函数声明 ====================void TSREventQueue_Init(TSREventQueue* const me);void TSREventQueue_Cleanup(TSREventQueue* const me);void TSREventQueue_isEmpty(TSREventQueue* const me);int TSREventQueue_isFull(TSREventQueue* const me);
// 核心操作:入队和出队int TSREventQueue_post(TSREventQueue* const me, Event e);Event TSREventQueue_pull(TSREventQueue* const me);
// 互斥锁相关struct Mutex* TSREventQueue_getItsMutex(const TSREventQueue* const me);void TSREventQueue_setItsMutex(TSREventQueue* const me, struct Mutex* p_Mutex);
// ==================== TSREventQueue.c 实现 ====================#include "TSREventQueue.h"#include "Mutex.h"
// 清理关联关系的静态函数static void cleanUpRelations(TSREventQueue* const me);
/** * 初始化事件队列 * 设置队列为空状态,初始化头尾指针 */void TSREventQueue_Init(TSREventQueue* const me) { me->head = 0; me->size = 0; me->tail = 0; me->itsMutex = NULL;}
/** * 清理事件队列 * 释放相关资源 */void TSREventQueue_Cleanup(TSREventQueue* const me) { cleanUpRelations(me);}
/** * 检查队列是否为空 */int TSREventQueue_isEmpty(TSREventQueue* const me) { return me->size == 0;}
/** * 检查队列是否已满 */int TSREventQueue_isFull(TSREventQueue* const me) { return me->size == QSIZE - 1;}
/** * 向队列中添加事件(线程安全) * * 关键实现细节: * 1. 获取互斥锁 * 2. 检查队列是否已满 * 3. 添加事件到队尾 * 4. 更新队尾指针(循环队列) * 5. 释放互斥锁并发送信号 */int TSREventQueue_post(TSREventQueue* const me, Event e) { Mutex_lock(me->itsMutex); // 加锁
if (!TSREventQueue_isFull(me)) { me->queue[me->head] = e; me->head = (me->head + 1) % QSIZE; // 循环队列 me->size += 1; Mutex_release(me->itsMutex); postSignal(); // 发送信号通知等待线程 return 1; } else { Mutex_release(me->itsMutex); return 0; }}
/** * 从队列中取出事件(线程安全) * 只有在有事件等待时才调用 */Event TSREventQueue_pull(TSREventQueue* const me) { Event e; Mutex_lock(me->itsMutex);
if (!TSREventQueue_isEmpty()) { e = me->queue[me->tail]; me->tail = (me->tail + 1) % QSIZE; // 循环队列 size -= 1; }
Mutex_release(me->itsMutex); return e;}
// ==================== TokenizerSyncSingleReceptor 定义 ====================// TSRSyncSingleReceptor.h#ifndef TSRSYNCSINGLERECEPTOR_H#define TSRSYNCSINGLERECEPTOR_H
#include "TokenizerSyncSingleReceptorPkg.h"
struct Mutex;
/** * 分词器结构体 * 使用单事件接收器模式实现 */typedef struct TokenizerSyncSingleReceptor { struct TokenizerSyncSingleReceptor* next; char ch; // 当前字符 double result; // 计算结果 TSTATETYPE stateID; // 主状态ID TSUBSTATETYPE subStateID; // 子状态ID double tensPlace; // 小数位数(0.1, 0.01等) struct Mutex* itsMutex; // 互斥锁} TokenizerSyncSingleReceptor;
// ==================== 状态动作函数声明 ====================// 进入状态时的动作void TokenizerSyncSingleReceptor_enter_GotNumber( TokenizerSyncSingleReceptor* const me);
void TokenizerSyncSingleReceptor_enter_NoNumber( TokenizerSyncSingleReceptor* const me);
void TokenizerSyncSingleReceptor_enter_ProcessingFractionalPart( TokenizerSyncSingleReceptor* const me);
void TokenizerSyncSingleReceptor_enter_ProcessingWholePart( TokenizerSyncSingleReceptor* const me);
// 退出状态时的动作void TokenizerSyncSingleReceptor_exit_GotNumber( TokenizerSyncSingleReceptor* const me);
void TokenizerSyncSingleReceptor_exit_NoNumber( TokenizerSyncSingleReceptor* const me);
void TokenizerSyncSingleReceptor_exit_ProcessingFractionalPart( TokenizerSyncSingleReceptor* const me);
void TokenizerSyncSingleReceptor_exit_ProcessingWholePart( TokenizerSyncSingleReceptor* const me);
// 核心函数:事件分发器void TokenizerSyncSingleReceptor_eventDispatch( TokenizerSyncSingleReceptor* const me, Event e);
// ==================== TSRSyncSingleReceptor.c 实现 ====================#include "TSRSyncSingleReceptor.h"#include "Mutex.h"
/** * 进入"获得数字"状态 * 初始化tensPlace为10(用于处理小数) */void TokenizerSyncSingleReceptor_enter_GotNumber( TokenizerSyncSingleReceptor* const me) { me->tensPlace = 10.0;}
/** * 进入"无数字"状态 * 重置结果为0 */void TokenizerSyncSingleReceptor_enter_NoNumber( TokenizerSyncSingleReceptor* const me) { me->result = 0.0;}
/** * 进入"处理小数部分"状态 * 此处可添加特定的初始化逻辑 */void TokenizerSyncSingleReceptor_enter_ProcessingFractionalPart( TokenizerSyncSingleReceptor* const me) { /* 进入小数部分处理的准备工作 */}
/** * 进入"处理整数部分"状态 * 结果乘以10并加上新数字 */void TokenizerSyncSingleReceptor_enter_ProcessingWholePart( TokenizerSyncSingleReceptor* const me) { me->result = me->result * 10 + digit(me->ch);}
/** * 退出"获得数字"状态 * 设置子状态为空 */void TokenizerSyncSingleReceptor_exit_GotNumber( TokenizerSyncSingleReceptor* const me) { me->subStateID = NULL_SSTATE;}
/** * 退出"无数字"状态 * 清理工作(如果需要) */void TokenizerSyncSingleReceptor_exit_NoNumber( TokenizerSyncSingleReceptor* const me) { /* 退出时的清理工作 */}
/** * 退出"处理小数部分"状态 * 清理小数处理相关的状态 */void TokenizerSyncSingleReceptor_exit_ProcessingFractionalPart( TokenizerSyncSingleReceptor* const me) { /* 清理小数部分处理 */}
/** * 退出"处理整数部分"状态 * 清理整数处理相关的状态 */void TokenizerSyncSingleReceptor_exit_ProcessingWholePart( TokenizerSyncSingleReceptor* const me) { /* 清理整数部分处理 */}
/** * 初始化分词器 * 设置初始状态和默认值 */void TokenizerSyncSingleReceptor_Init( TokenizerSyncSingleReceptor* const me) { me->ch = 'x'; // 初始字符 me->result = 0.0; // 初始结果 me->tensPlace = 10.0; // 小数位初始值 me->itsMutex = NULL; // 互斥锁 me->stateID = NONUMBER_STATE; // 初始状态:无数字 me->subStateID = NULL_SSTATE; // 初始子状态:空}
/** * 核心函数:事件分发器 * 根据事件类型和当前状态执行相应的处理逻辑 * * 这是单事件接收器模式的核心: * - 每个事件类型有自己的处理分支 * - 在每个分支内根据当前状态决定行为 * - 状态转换逻辑分散在各个case中 */void TokenizerSyncSingleReceptor_eventDispatch( TokenizerSyncSingleReceptor* const me, Event e) {
Mutex_lock(me->itsMutex); // 加锁保证线程安全
switch(e.eType) {
// ========== 处理数字事件 ========== case EVDIGIT: switch(me->stateID) { case NONUMBER_STATE: // 从"无数字"转换到"获得数字"状态 TokenizerSyncSingleReceptor_exit_NoNumber(me); me->ch = e.ed.c; // 保存数字字符 TokenizerSyncSingleReceptor_enter_GotNumber(me); me->stateID = GOTNUMBER_STATE;
// 进入子状态:处理整数部分 TokenizerSyncSingleReceptor_enter_ProcessingWholePart(me); me->subStateID = PROCESSINGWHOLEPART_SSTATE; printf("Current value of result: %g\n", me->result); break;
case GOTNUMBER_STATE: // 已经在"获得数字"状态,根据子状态处理 switch(me->subStateID) { case PROCESSINGWHOLEPART_SSTATE: // 继续处理整数部分 TokenizerSyncSingleReceptor_exit_ProcessingWholePart(me); me->ch = e.ed.c; TokenizerSyncSingleReceptor_enter_ProcessingWholePart(me); printf("Current value of result: %g\n", me->result); break;
case PROCESSINGFRACTIONALPART_SSTATE: // 处理小数部分 TokenizerSyncSingleReceptor_exit_ProcessingFractionalPart(me); me->ch = e.ed.c; me->result += digit(me->ch) / me->tensPlace; me->tensPlace *= 10.0; // 移动小数位 TokenizerSyncSingleReceptor_enter_ProcessingFractionalPart(me); printf("Current value of result: %g\n", me->result); break; } break; } break;
// ========== 处理小数点事件 ========== case EVDOT: me->ch = '.'; switch(me->stateID) { case NONUMBER_STATE: // 小数点前没有数字,转换到获得数字状态(默认子状态) TokenizerSyncSingleReceptor_exit_NoNumber(me); TokenizerSyncSingleReceptor_enter_GotNumber(me); me->stateID = GOTNUMBER_STATE;
// 进入处理小数部分子状态 TokenizerSyncSingleReceptor_enter_ProcessingFractionalPart(me); me->subStateID = PROCESSINGFRACTIONALPART_SSTATE; break;
case GOTNUMBER_STATE: switch(me->subStateID) { case PROCESSINGWHOLEPART_SSTATE: // 从整数部分转到小数部分 TokenizerSyncSingleReceptor_exit_ProcessingWholePart(me); TokenizerSyncSingleReceptor_enter_ProcessingFractionalPart(me); me->subStateID = PROCESSINGFRACTIONALPART_SSTATE; break;
case PROCESSINGFRACTIONALPART_SSTATE: // 已经在处理小数,第二个小数点可能是错误 TokenizerSyncSingleReceptor_exit_ProcessingFractionalPart(me); break; } break; } break;
// ========== 处理空白字符事件 ========== case EVWHITESPACE: case EVENDOFSTRING: switch(me->stateID) { case GOTNUMBER_STATE: // 数字结束,根据子状态做清理 switch(me->subStateID) { case PROCESSINGWHOLEPART_SSTATE: TokenizerSyncSingleReceptor_exit_ProcessingWholePart(me); break;
case PROCESSINGFRACTIONALPART_SSTATE: TokenizerSyncSingleReceptor_exit_ProcessingFractionalPart(me); break; }
// 退出"获得数字"状态,返回"无数字"状态 TokenizerSyncSingleReceptor_exit_GotNumber(me); printf("Number: %g\n", me->result); TokenizerSyncSingleReceptor_enter_NoNumber(me); me->stateID = NONUMBER_STATE; break; } break;
default: // 未知事件类型,忽略 break; }
Mutex_release(me->itsMutex); // 释放锁}
// ==================== 辅助函数 ====================
/** * 将字符转换为数字 * '0' -> 0, '1' -> 1, ..., '9' -> 9 */int digit(char c) { return c - '0';}
/** * 主循环函数 * 等待事件并处理,直到收到结束信号 */void TokenizerAsyncSingleReceptor_taskLoop() { while(1) { waitOnSignal(); // 等待事件信号
while(!TSREventQueue_isEmpty->itsTSREventQueue)) { // 处理队列中的所有事件 TokenizerAsyncSingleReceptor_eventDispatch( TokenizerAsyncSingleReceptor_pull(me->itsTSREventQueue) ); } }}
// ==================== 使用示例 ====================/* * 示例:处理输入 "12.34 " * * 1. 接收 '1' (EVDIGIT) * - 状态:NONUMBER_STATE -> GOTNUMBER_STATE * - 子状态:-> PROCESSINGWHOLEPART_SSTATE * - result = 1 * * 2. 接收 '2' (EVDIGIT) * - 状态:保持 GOTNUMBER_STATE * - 子状态:保持 PROCESSINGWHOLEPART_SSTATE * - result = 12 * * 3. 接收 '.' (EVDOT) * - 状态:保持 GOTNUMBER_STATE * - 子状态:PROCESSINGWHOLEPART_SSTATE -> PROCESSINGFRACTIONALPART_SSTATE * * 4. 接收 '3' (EVDIGIT) * - 状态:保持 GOTNUMBER_STATE * - 子状态:保持 PROCESSINGFRACTIONALPART_SSTATE * - result = 12.3 * * 5. 接收 '4' (EVDIGIT) * - 状态:保持 GOTNUMBER_STATE * - 子状态:保持 PROCESSINGFRACTIONALPART_SSTATE * - result = 12.34 * * 6. 接收 ' ' (EVWHITESPACE) * - 状态:GOTNUMBER_STATE -> NONUMBER_STATE * - 输出:Number: 12.34 */多事件接收器模式(MERSM)
跳转到“多事件接收器模式(MERSM)”多事件接收器模式是对单事件接收器模式的改进。核心思想是为每个状态创建独立的事件处理器,而不是将所有逻辑集中在一个巨大的事件分发函数中。
给每个状态单独配一把钥匙(事件处理器),谁来敲门就用哪把钥匙开门,不再让一把万能钥匙(巨大的 switch-case)管所有门。 1️⃣ 单事件接收器 = 一把万能钥匙
事件分发函数├─ switch(state){ ├─ 状态A:处理事件X、Y、Z ├─ 状态B:处理事件X、Y、Z └─ 状态C:处理事件X、Y、Z}新增一个事件或状态,都要回到这个巨无霸函数里改,越来越臃肿。
2️⃣ MERSM = 每扇门一把钥匙
状态A → handleA_eventX(), handleA_eventY(), handleA_eventZ()状态B → handleB_eventX(), handleB_eventY(), handleB_eventZ()状态C → handleC_eventX(), handleC_eventY(), handleC_eventZ()新增状态只需再配一把钥匙,旧钥匙完全不动;代码按“状态”分文件,一眼看到底。
抽象 状态机的MERSM方式实现很可能是同步状态机最常见的实现。通常是最简单的,因为每个事件接收器本身仅考虑处理单一事件以及执行相关动作。
问题 该模式解决同步状态机的简单健壮实现的问题。
模式结构


效果
该模式通过将状态逻辑分成一组事件接收器简化了实现。其中每一个都依赖于状态提供switch-case语句来实现相应的行为。模式总是专门适用于同步状态机,因为在一般情况下,事件队列分析它们管理数据的内部内容,因此,如果多于一个,则不知道该调用哪个事件接收器。
实现策略 使用if-then语句替代switch-case的变体:
switch(state) { case IDLE: ... break; case RUN: ... break; case ERROR: ... break;}
// 换成if (state == IDLE) handle_IDLE_event();else if (state == RUN) handle_RUN_event();else if (state == ERROR) handle_ERROR_event();示例
/* * 多事件接收器模式(MERSM)- 计算器分词器示例 * * 核心改进:每个状态有自己的事件处理函数,而不是一个巨大的eventDispatch * 这样使得代码更模块化,更易维护 */
// ==================== 状态和事件类型定义 ====================// 代码清单 5-11 TokenizeMultiReceptor 使用的基本类型
typedef enum TSTATETYPE { NULL_STATE, NONUMBER_STATE, // 无数字状态 GOTNUMBER_STATE // 有数字状态} TSTATETYPE;
typedef enum TSUBSTATETYPE { NULL_SSTATE, PROCESSINGWHOLEPART_SSTATE, // 处理整数部分 PROCESSINGFRACTIONALPART_SSTATE // 处理小数部分} TSUBSTATETYPE;
// 辅助函数:字符转数字int digit(char c) { return c - '0';}
// ==================== TokenizerMultiReceptor.h ====================// 代码清单 5-12#ifndef TOKENIZERMULTIRECEPTOR_H#define TOKENIZERMULTIRECEPTOR_H
#include <stdio.h>#include <stdlib.h>
struct Mutex;
/** * 多事件接收器模式的分词器 * 关键改进:每个事件类型有独立的处理函数 */typedef struct TokenizerMultiReceptor TokenizerMultiReceptor;struct TokenizerMultiReceptor { char ch; // 当前字符 double result; // 计算结果 TSTATETYPE stateID; // 主状态ID TSUBSTATETYPE subStateID; // 子状态ID double tensPlace; // 小数位(10.0, 0.1, 0.01...) struct Mutex* itsMutex; // 互斥锁};
// ==================== 构造和析构函数 ====================void TokenizerMultiReceptor_Cleanup(TokenizerMultiReceptor* const me);void TokenizerMultiReceptor_Init(TokenizerMultiReceptor* const me);TokenizerMultiReceptor* TokenizerMultiReceptor_Create(void);void TokenizerMultiReceptor_Destroy(TokenizerMultiReceptor* const me);
// ==================== 多事件接收器(核心改进) ====================/* * 关键设计:为每个事件类型提供独立的处理函数 * 这避免了单一巨大的switch-case结构 */
// 处理数字事件void TokenizerMultiReceptor_evDigit(TokenizerMultiReceptor* const me, char c);
// 处理小数点事件void TokenizerMultiReceptor_evDot(TokenizerMultiReceptor* const me);
// 处理字符串结束事件void TokenizerMultiReceptor_evEndOfString(TokenizerMultiReceptor* const me);
// 处理空白字符事件void TokenizerMultiReceptor_evWhiteSpace(TokenizerMultiReceptor* const me);
// ==================== 状态进入动作 ====================void TokenizerMultiReceptor_enter_GotNumber(TokenizerMultiReceptor* const me);void TokenizerMultiReceptor_enter_NoNumber(TokenizerMultiReceptor* const me);void TokenizerMultiReceptor_enter_ProcessingFractionalPart(TokenizerMultiReceptor* const me);void TokenizerMultiReceptor_enter_ProcessingWholePart(TokenizerMultiReceptor* const me);
// ==================== 状态退出动作 ====================void TokenizerMultiReceptor_exit_GotNumber(TokenizerMultiReceptor* const me);void TokenizerMultiReceptor_exit_NoNumber(TokenizerMultiReceptor* const me);void TokenizerMultiReceptor_exit_ProcessingFractionalPart(TokenizerMultiReceptor* const me);void TokenizerMultiReceptor_exit_ProcessingWholePart(TokenizerMultiReceptor* const me);
// Mutex相关struct Mutex* TokenizerMultiReceptor_getItsMutex(const TokenizerMultiReceptor* const me);void TokenizerMultiReceptor_setItsMutex(TokenizerMultiReceptor* const me, struct Mutex* p_Mutex);
#endif
// ==================== TokenizerMultiReceptor.c ====================// 代码清单 5-13#include "TokenizerMultiReceptor.h"#include "Mutex.h"
static void cleanUpRelations(TokenizerMultiReceptor* const me);
/** * 清理函数 */void TokenizerMultiReceptor_Cleanup(TokenizerMultiReceptor* const me) { cleanUpRelations(me);}
/** * 初始化分词器 * 设置初始状态和默认值 */void TokenizerMultiReceptor_Init(TokenizerMultiReceptor* const me) { me->ch = 'x'; me->result = 0.0; me->tensPlace = 10.0; me->itsMutex = NULL;
/* 初始化状态变量 */ me->stateID = NONUMBER_STATE; // 初始为无数字状态 me->subStateID = NULL_SSTATE; // 无子状态}
/** * 处理数字事件(evDigit) * 核心改进:这个函数只处理数字事件,逻辑更清晰 * * @param me 分词器实例 * @param c 数字字符 */void TokenizerMultiReceptor_evDigit(TokenizerMultiReceptor* const me, char c) { Mutex_lock(me->itsMutex);
switch (me->stateID) { case NONUMBER_STATE: /* 从无数字状态转换到有数字状态 */ TokenizerMultiReceptor_exit_NoNumber(me); me->ch = c; TokenizerMultiReceptor_enter_GotNumber(me); me->stateID = GOTNUMBER_STATE;
/* 进入处理整数部分的子状态 */ TokenizerMultiReceptor_enter_ProcessingWholePart(me); me->subStateID = PROCESSINGWHOLEPART_SSTATE; printf("Current value of result: %g\n", me->result); break;
case GOTNUMBER_STATE: /* 已经在有数字状态,根据子状态处理 */ switch (me->subStateID) { case PROCESSINGWHOLEPART_SSTATE: /* 继续处理整数部分 */ TokenizerMultiReceptor_exit_ProcessingWholePart(me); me->ch = c; TokenizerMultiReceptor_enter_ProcessingWholePart(me); printf("Current value of result: %g\n", me->result); break;
case PROCESSINGFRACTIONALPART_SSTATE: /* 处理小数部分 */ TokenizerMultiReceptor_exit_ProcessingFractionalPart(me); me->ch = c; me->result += digit(me->ch) / me->tensPlace; me->tensPlace *= 10.0; TokenizerMultiReceptor_enter_ProcessingFractionalPart(me); printf("Current value of result: %g\n", me->result); break; } break; }
Mutex_release(me->itsMutex);}
/** * 处理小数点事件(evDot) * 独立的小数点处理逻辑 */void TokenizerMultiReceptor_evDot(TokenizerMultiReceptor* const me) { Mutex_lock(me->itsMutex); me->ch = '.';
switch (me->stateID) { case NONUMBER_STATE: /* 小数点前无数字,转到有数字状态并开始处理小数 */ TokenizerMultiReceptor_exit_NoNumber(me); TokenizerMultiReceptor_enter_GotNumber(me); me->stateID = GOTNUMBER_STATE;
TokenizerMultiReceptor_enter_ProcessingFractionalPart(me); me->subStateID = PROCESSINGFRACTIONALPART_SSTATE; break;
case GOTNUMBER_STATE: switch (me->subStateID) { case PROCESSINGWHOLEPART_SSTATE: /* 从整数部分转到小数部分 */ TokenizerMultiReceptor_exit_ProcessingWholePart(me); TokenizerMultiReceptor_enter_ProcessingFractionalPart(me); me->subStateID = PROCESSINGFRACTIONALPART_SSTATE; break;
case PROCESSINGFRACTIONALPART_SSTATE: /* 已经在处理小数,第二个小数点是错误 */ TokenizerMultiReceptor_exit_ProcessingFractionalPart(me); break; } break; }
Mutex_release(me->itsMutex);}
/** * 处理字符串结束事件(evEndOfString) * 结束数字解析并输出结果 */void TokenizerMultiReceptor_evEndOfString(TokenizerMultiReceptor* const me) { Mutex_lock(me->itsMutex);
switch (me->stateID) { case GOTNUMBER_STATE: /* 根据子状态执行相应的退出动作 */ switch (me->subStateID) { case PROCESSINGWHOLEPART_SSTATE: TokenizerMultiReceptor_exit_ProcessingWholePart(me); break;
case PROCESSINGFRACTIONALPART_SSTATE: TokenizerMultiReceptor_exit_ProcessingFractionalPart(me); break; }
/* 输出结果并返回无数字状态 */ TokenizerMultiReceptor_exit_GotNumber(me); printf("Number: %g\n", me->result); TokenizerMultiReceptor_enter_NoNumber(me); me->stateID = NONUMBER_STATE; break; }
Mutex_release(me->itsMutex);}
/** * 处理空白字符事件(evWhiteSpace) * 与字符串结束事件类似的处理 */void TokenizerMultiReceptor_evWhiteSpace(TokenizerMultiReceptor* const me) { Mutex_lock(me->itsMutex);
switch (me->stateID) { case GOTNUMBER_STATE: switch (me->subStateID) { case PROCESSINGWHOLEPART_SSTATE: TokenizerMultiReceptor_exit_ProcessingWholePart(me); break;
case PROCESSINGFRACTIONALPART_SSTATE: TokenizerMultiReceptor_exit_ProcessingFractionalPart(me); break; }
TokenizerMultiReceptor_exit_GotNumber(me); printf("Number: %g\n", me->result); TokenizerMultiReceptor_enter_NoNumber(me); me->stateID = NONUMBER_STATE; break; }
Mutex_release(me->itsMutex);}
// ==================== 状态进入和退出动作 ====================
/** * 进入"有数字"状态的动作 */void TokenizerMultiReceptor_enter_GotNumber(TokenizerMultiReceptor* const me) { me->tensPlace = 10.0;}
/** * 进入"无数字"状态的动作 */void TokenizerMultiReceptor_enter_NoNumber(TokenizerMultiReceptor* const me) { me->result = 0.0;}
/** * 进入"处理小数部分"状态的动作 */void TokenizerMultiReceptor_enter_ProcessingFractionalPart( TokenizerMultiReceptor* const me) { /* 特定的初始化(如果需要) */}
/** * 进入"处理整数部分"状态的动作 */void TokenizerMultiReceptor_enter_ProcessingWholePart( TokenizerMultiReceptor* const me) { me->result = me->result * 10 + digit(me->ch);}
/** * 退出"有数字"状态的动作 */void TokenizerMultiReceptor_exit_GotNumber(TokenizerMultiReceptor* const me) { me->subStateID = NULL_SSTATE;}
/** * 退出"无数字"状态的动作 */void TokenizerMultiReceptor_exit_NoNumber(TokenizerMultiReceptor* const me) { /* 清理动作(如果需要) */}
/** * 退出"处理小数部分"状态的动作 */void TokenizerMultiReceptor_exit_ProcessingFractionalPart( TokenizerMultiReceptor* const me) { /* 清理动作 */}
/** * 退出"处理整数部分"状态的动作 */void TokenizerMultiReceptor_exit_ProcessingWholePart( TokenizerMultiReceptor* const me) { /* 清理动作 */}
// ==================== 辅助函数 ====================
TokenizerMultiReceptor* TokenizerMultiReceptor_Create(void) { TokenizerMultiReceptor* me = (TokenizerMultiReceptor*) malloc(sizeof(TokenizerMultiReceptor)); if(me != NULL) { TokenizerMultiReceptor_Init(me); } return me;}
void TokenizerMultiReceptor_Destroy(TokenizerMultiReceptor* const me) { if(me != NULL) { TokenizerMultiReceptor_Cleanup(me); free(me); }}
struct Mutex* TokenizerMultiReceptor_getItsMutex( const TokenizerMultiReceptor* const me) { return (struct Mutex*)me->itsMutex;}
void TokenizerMultiReceptor_setItsMutex(TokenizerMultiReceptor* const me, struct Mutex* p_Mutex) { me->itsMutex = p_Mutex;}
static void cleanUpRelations(TokenizerMultiReceptor* const me) { if(me->itsMutex != NULL) { me->itsMutex = NULL; }}
// ==================== 使用示例 ====================/* * 客户端使用方式的关键改进: * 不再调用单一的eventDispatch,而是根据事件类型调用相应的处理函数 */
void TMRClient_example() { TokenizerMultiReceptor* tokenizer = TokenizerMultiReceptor_Create();
// 处理 "12.34 " 输入序列
// 处理 '1' - 调用数字事件处理器 TokenizerMultiReceptor_evDigit(tokenizer, '1');
// 处理 '2' - 调用数字事件处理器 TokenizerMultiReceptor_evDigit(tokenizer, '2');
// 处理 '.' - 调用小数点事件处理器 TokenizerMultiReceptor_evDot(tokenizer);
// 处理 '3' - 调用数字事件处理器 TokenizerMultiReceptor_evDigit(tokenizer, '3');
// 处理 '4' - 调用数字事件处理器 TokenizerMultiReceptor_evDigit(tokenizer, '4');
// 处理 ' ' - 调用空白字符事件处理器 TokenizerMultiReceptor_evWhiteSpace(tokenizer);
// 输出: Number: 12.34
TokenizerMultiReceptor_Destroy(tokenizer);}
/* * ==================== 模式对比分析 ==================== * * 单事件接收器模式 vs 多事件接收器模式 * * 单事件接收器(SERSM): * - 一个巨大的 eventDispatch(Event e) 函数 * - 先按事件类型分支,再按状态分支 * - 所有逻辑集中在一处 * - 代码结构: * switch(e.type) { * case EVENT1: * switch(state) {...} * case EVENT2: * switch(state) {...} * } * * 多事件接收器(MERSM): * - 每个事件类型有独立的处理函数 * - evDigit(), evDot(), evWhiteSpace(), evEndOfString() * - 每个函数内部只处理相关状态 * - 代码结构更清晰,更模块化 * * 优势: * 1. 模块化:每个事件处理器独立,易于理解和维护 * 2. 可扩展:添加新事件只需添加新函数 * 3. 可读性:避免嵌套过深的switch-case * 4. 测试友好:可以独立测试每个事件处理器 * * 劣势: * 1. 代码重复:不同事件处理器可能有相似逻辑 * 2. 状态逻辑分散:需要查看多个函数才能理解完整的状态行为 */状态表模式
跳转到“状态表模式”状态表模式是处理状态机的一种优雅方式,通过二维表格来组织状态转换信息,避免了前面模式中的大量条件判断代码。
把整台状态机拍成一张 Excel 表,行是‘现在在哪’,列是‘来了什么事’,格子告诉你:要不要换状态、先做什么动作——查表就完事,不写 if/else。
1️⃣ 没有状态表 = 千层 if/switch
switch(state){ case IDLE: if(e==START) ...; else if(e==STOP) ...; break; case RUN: if(e==START) ...; else if(e==STOP) ...; break; ...}每加一行状态或事件,就要翻遍全文件。
2️⃣ 有了状态表 = 一张二维表
START STOPIDLE ├─动作→RUN ├─动作→IDLERUN ├─动作→RUN ├─动作→IDLE新增状态/事件 → 只往表里加一行/列,不动老代码。
3️⃣ 表里的格子 = 三件套
{ guard?, exit, transit, entry, nextState }- guard:条件不满足就原地不动
- exit:离开旧状态前收尾
- transit:过渡动作
- entry:进入新状态前准备
抽象 状态表模式使用二维数组来存储状态转换信息。这个表通常用状态x事件构建表格;状态变量是第一个索引,并且收到的事件D是第二个索引。表的内容是一个包含相应动作和监护条件的链接以及需要执行转换的新状态的结构。这需要一个比其他状态实现模式更详细的数据结构。
问题 通过状态表模式解决的问题是为潜在的大的、平的状态空间或者易于做成这样的状态空间实现状态机。并且,当你关心状态机的性能、事件的响应时间、状态空间大小的独立性,但是你不关心初始化状态机需要多少时间,该模式也是适用的。
模式结构

关键设计特点
// 1. 查表代替条件判断TableEntry te = table[currentState][eventType];
// 2. 标准的动作执行序列if (guardCondition) { exitAction();// 退出当前状态 transitionAction();// 执行转换动作 entryAction();// 进入新状态 currentState = newState; }
// 3. 函数指针提供灵活性if (actionPtr->nParams == 0) actionPtr->a0(me);// 无参数版本 else actionPtr->a1(me, c);// 带参数版本
示例
/* * 状态表模式 - 通过二维表格管理状态转换 * * 核心思想:用表格数据代替嵌套的switch-case语句 * 表格的行代表状态,列代表事件,单元格包含动作和新状态 */
// ==================== StateTablePattern.h ====================// 代码清单 5-14#ifndef STATETABLEPATTERN_H#define STATETABLEPATTERN_H
// 状态枚举定义 - 注意这里合并了主状态和子状态typedef enum TSTATETYPE { NULL_STATE, NONUMBER_STATE, GN_PROCESSINGWHOLEPART_STATE, // GotNumber状态的整数子状态 GN_PROCESSINGFRACTIONALPART_STATE // GotNumber状态的小数子状态} TSTATETYPE;
// 事件类型枚举typedef enum EventType { EVDIGIT, EVDOT, EVWHITESPACE, EVENDOFSTRING} EventType;
// 事件结构体typedef struct Event { EventType eType; union eventData { char c; } ed;} Event;
// ==================== 函数指针类型定义 ====================
// ActionPtr0: 只接受me对象指针,无其他参数typedef void (*ActionPtr0)(void*);
// ActionPtr1: 接受me对象指针和一个字符参数// 客户端必须在事件中发送字符数据typedef void (*ActionPtr1)(void*, char);
// ActionType: 函数指针的联合体typedef union ActionType { ActionPtr0 a0; ActionPtr1 a1;} ActionType;
// aPtr: ActionType的指针类型typedef ActionType* ActionPtr;
// ==================== 守卫条件类型 ====================
// GuardType: 守卫函数,返回布尔值(0=FALSE, 非0=TRUE)// 用于决定是否执行转换typedef int (*GuardType)(void*);
// ==================== 状态表项结构 ====================
typedef struct TableEntryType { ActionPtr entryActionPtr; // 进入动作 ActionPtr exitActionPtr; // 退出动作 GuardType guardPtr; // 守卫条件 TSTATETYPE newState; // 新状态 ActionPtr transActionPtr; // 转换动作} TableEntryType;
// 辅助函数int digit(char c) { return c - '0';}
#endif
// ==================== TokenizerStateTable.h ====================// 代码清单 5-15#ifndef TOKENIZERSTATTABLE_H#define TOKENIZERSTATTABLE_H
#include "StateTablePattern.h"
struct Mutex;
// TokenizerStateTable 结构体typedef struct TokenizerStateTable TokenizerStateTable;struct TokenizerStateTable { char ch; double result; TSTATETYPE stateID;
// 状态表:[状态数][事件数]的二维数组 // 这是模式的核心 - 用表格代替条件判断 TableEntryType table[GN_PROCESSINGFRACTIONALPART_STATE+1][EVENDOFSTRING+1];
double tensPlace; struct Mutex* itsMutex;};
// ==================== 函数声明 ====================
// 构造和析构void TokenizerStateTable_Init(TokenizerStateTable* const me);void TokenizerStateTable_Cleanup(TokenizerStateTable* const me);TokenizerStateTable* TokenizerStateTable_Create(void);void TokenizerStateTable_Destroy(TokenizerStateTable* const me);
// 核心操作 - eventDispatch现在查表而不是条件判断void TokenizerStateTable_eventDispatch(TokenizerStateTable* const me, Event e);
// 状态进入动作void TokenizerStateTable_enter_GotNumber(TokenizerStateTable* const me);void TokenizerStateTable_enter_NoNumber(TokenizerStateTable* const me);void TokenizerStateTable_enter_ProcessingFractionalPart(TokenizerStateTable* const me);void TokenizerStateTable_enter_ProcessingWholePart(TokenizerStateTable* const me);
// 状态退出动作void TokenizerStateTable_exit_GotNumber(TokenizerStateTable* const me);void TokenizerStateTable_exit_NoNumber(TokenizerStateTable* const me);void TokenizerStateTable_exit_ProcessingFractionalPart(TokenizerStateTable* const me);void TokenizerStateTable_exit_ProcessingWholePart(TokenizerStateTable* const me);
// 辅助函数void TokenizerStateTable_assignCh(TokenizerStateTable* const me, char c);void TokenizerStateTable_NoNum2GN(TokenizerStateTable* const me, char c);void TokenizerStateTable_Frac2Frac(TokenizerStateTable* const me, char c);void TokenizerStateTable_printResult(TokenizerStateTable* const me);
// Mutex相关struct Mutex* TokenizerStateTable_getItsMutex(const TokenizerStateTable* const me);void TokenizerStateTable_setItsMutex(TokenizerStateTable* const me, struct Mutex* p_Mutex);
#endif
// ==================== TokenizerStateTable.c ====================// 代码清单 5-16#include "TokenizerStateTable.h"#include "Mutex.h"#include <stdio.h>#include <stdlib.h>
static void cleanUpRelations(TokenizerStateTable* const me);
/** * 初始化TokenizerStateTable * 最重要的部分:构建状态转换表 */void TokenizerStateTable_Init(TokenizerStateTable* const me) { me->ch = 'x'; me->result = 0.0; me->tensPlace = 10.0; me->itsMutex = NULL; TSTATETYPE st; EventType ev; TableEntryType te;
// ==================== 初始化表格为空状态 ==================== // 将整个表格初始化为NULL条件 for (st = NULL_STATE; st <= GN_PROCESSINGFRACTIONALPART_STATE; st++) { for (ev = EVDIGIT; ev <= EVENDOFSTRING; ev++) { me->table[st][ev].newState = NULL_STATE; me->table[st][ev].guardPtr = (GuardType)NULL; me->table[st][ev].exitActionPtr = NULL; me->table[st][ev].transActionPtr = NULL; me->table[st][ev].entryActionPtr = NULL; } }
// ==================== 配置具体的状态转换 ====================
/* ===== 1. NONUMBER_STATE -> GN_PROCESSINGWHOLEPART_STATE (数字事件) ===== */ te.guardPtr = (GuardType)NULL; // 无守卫条件 te.exitActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.exitActionPtr->nParams = 0; te.exitActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_exit_NoNumber; te.transActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.transActionPtr->nParams = 1; te.transActionPtr->aPtr.a1 = (ActionPtr1)TokenizerStateTable_NoNum2GN; te.entryActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.entryActionPtr->nParams = 0; te.entryActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_enter_ProcessingWholePart; te.newState = GN_PROCESSINGWHOLEPART_STATE; me->table[NONUMBER_STATE][EVDIGIT] = te;
/* ===== 2. GN_PROCESSINGWHOLEPART_STATE 自转换 (数字事件) ===== */ te.guardPtr = (GuardType)NULL; te.exitActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.exitActionPtr->nParams = 0; te.exitActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_exit_ProcessingWholePart; te.transActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.transActionPtr->nParams = 1; te.transActionPtr->aPtr.a1 = (ActionPtr1)TokenizerStateTable_assignCh; te.entryActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.entryActionPtr->nParams = 0; te.entryActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_enter_ProcessingWholePart; te.newState = GN_PROCESSINGWHOLEPART_STATE; me->table[GN_PROCESSINGWHOLEPART_STATE][EVDIGIT] = te;
/* ===== 3. NONUMBER_STATE -> GN_PROCESSINGFRACTIONALPART_STATE (小数点事件) ===== */ te.guardPtr = (GuardType)NULL; te.exitActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.exitActionPtr->nParams = 0; te.exitActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_exit_NoNumber; te.transActionPtr = (ActionPtr)NULL; te.entryActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.entryActionPtr->nParams = 0; te.entryActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_enter_ProcessingFractionalPart; te.newState = GN_PROCESSINGFRACTIONALPART_STATE; me->table[NONUMBER_STATE][EVDOT] = te;
/* ===== 4. GN_PROCESSINGWHOLEPART_STATE -> GN_PROCESSINGFRACTIONALPART_STATE (小数点) ===== */ te.guardPtr = (GuardType)NULL; te.exitActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.exitActionPtr->nParams = 0; te.exitActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_exit_ProcessingWholePart; te.transActionPtr = (ActionPtr)NULL; te.entryActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.entryActionPtr->nParams = 0; te.entryActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_enter_ProcessingFractionalPart; te.newState = GN_PROCESSINGFRACTIONALPART_STATE; me->table[GN_PROCESSINGWHOLEPART_STATE][EVDOT] = te;
/* ===== 5. GN_PROCESSINGFRACTIONALPART_STATE 自转换 (数字事件) ===== */ te.guardPtr = (GuardType)NULL; te.exitActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.exitActionPtr->nParams = 0; te.exitActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_exit_ProcessingFractionalPart; te.transActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.transActionPtr->nParams = 1; te.transActionPtr->aPtr.a1 = (ActionPtr1)TokenizerStateTable_Frac2Frac; te.entryActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.entryActionPtr->nParams = 0; te.entryActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_enter_ProcessingFractionalPart; te.newState = GN_PROCESSINGFRACTIONALPART_STATE; me->table[GN_PROCESSINGFRACTIONALPART_STATE][EVDIGIT] = te;
/* ===== 6. 处理空白符和字符串结束事件 - 返回NONUMBER_STATE ===== */ // GN_PROCESSINGWHOLEPART_STATE -> NONUMBER_STATE (空白符) te.guardPtr = (GuardType)NULL; te.exitActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.exitActionPtr->nParams = 0; te.exitActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_exit_ProcessingWholePart; te.transActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.transActionPtr->nParams = 0; te.transActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_printResult; te.entryActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.entryActionPtr->nParams = 0; te.entryActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_enter_NoNumber; te.newState = NONUMBER_STATE; me->table[GN_PROCESSINGWHOLEPART_STATE][EVWHITESPACE] = te;
// GN_PROCESSINGFRACTIONALPART_STATE -> NONUMBER_STATE (空白符) te.guardPtr = (GuardType)NULL; te.exitActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.exitActionPtr->nParams = 0; te.exitActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_exit_ProcessingFractionalPart; te.transActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.transActionPtr->nParams = 0; te.transActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_printResult; te.entryActionPtr = (ActionPtr)malloc(sizeof(ActionPtr)); te.entryActionPtr->nParams = 0; te.entryActionPtr->aPtr.a0 = (ActionPtr0)TokenizerStateTable_enter_NoNumber; te.newState = NONUMBER_STATE; me->table[GN_PROCESSINGFRACTIONALPART_STATE][EVWHITESPACE] = te;
// 同样配置EVENDOFSTRING事件... me->table[GN_PROCESSINGWHOLEPART_STATE][EVENDOFSTRING] = te; me->table[GN_PROCESSINGFRACTIONALPART_STATE][EVENDOFSTRING] = te;
/* 最后初始化为NONUMBER_STATE状态 */ me->stateID = NONUMBER_STATE; TokenizerStateTable_enter_NoNumber(me);}
/** * 核心函数:事件分发器 * 状态表模式的精髓 - 通过查表代替条件判断 */void TokenizerStateTable_eventDispatch(TokenizerStateTable* const me, Event e) { int takeTransition = 0; Mutex_lock(me->itsMutex);
/* 在表格边界内检查 */ if (me->stateID >= NULL_STATE && me->stateID <= GN_PROCESSINGFRACTIONALPART_STATE) { if (e.eType >= EVDIGIT && e.eType <= EVENDOFSTRING) { /* 存在当前状态和事件的有效转换吗? */ if (me->table[me->stateID][e.eType].newState != NULL_STATE) { /* 是否有守卫条件? */ if (me->table[me->stateID][e.eType].guardPtr == NULL) { /* 无守卫条件,TRUE表示"执行"转换 */ takeTransition = TRUE; } else { /* 有守卫条件,计算其值 */ takeTransition = (me->table[me->stateID][e.eType].guardPtr(me)); }
if (takeTransition) { /* 执行退出动作 */ if (me->table[me->stateID][e.eType].exitActionPtr != NULL) { if (me->table[me->stateID][e.eType].exitActionPtr->nParams == 0) { me->table[me->stateID][e.eType].exitActionPtr->aPtr.a0(me); } else { me->table[me->stateID][e.eType].exitActionPtr->aPtr.a1(me, e.ed.c); } }
/* 执行转换动作 */ if (me->table[me->stateID][e.eType].transActionPtr != NULL) { if (me->table[me->stateID][e.eType].transActionPtr->nParams == 0) { me->table[me->stateID][e.eType].transActionPtr->aPtr.a0(me); } else { me->table[me->stateID][e.eType].transActionPtr->aPtr.a1(me, e.ed.c); } }
/* 执行进入动作 */ if (me->table[me->stateID][e.eType].entryActionPtr != NULL) { if (me->table[me->stateID][e.eType].entryActionPtr->nParams == 0) { me->table[me->stateID][e.eType].entryActionPtr->aPtr.a0(me); } else { me->table[me->stateID][e.eType].entryActionPtr->aPtr.a1(me, e.ed.c); } }
/* 更新到新状态 */ me->stateID = me->table[me->stateID][e.eType].newState; } } } }
Mutex_release(me->itsMutex);}
// ==================== 状态动作实现 ====================
void TokenizerStateTable_enter_GotNumber(TokenizerStateTable* const me) { me->tensPlace = 10.0;}
void TokenizerStateTable_enter_NoNumber(TokenizerStateTable* const me) { me->result = 0.0;}
void TokenizerStateTable_enter_ProcessingFractionalPart(TokenizerStateTable* const me) { /* 进入小数处理状态 */}
void TokenizerStateTable_enter_ProcessingWholePart(TokenizerStateTable* const me) { me->result = me->result * 10 + digit(me->ch);}
void TokenizerStateTable_exit_GotNumber(TokenizerStateTable* const me) { /* 退出有数字状态 */}
void TokenizerStateTable_exit_NoNumber(TokenizerStateTable* const me) { /* 退出无数字状态 */}
void TokenizerStateTable_exit_ProcessingFractionalPart(TokenizerStateTable* const me) { /* 退出小数处理状态 */}
void TokenizerStateTable_exit_ProcessingWholePart(TokenizerStateTable* const me) { /* 退出整数处理状态 */}
// ==================== 辅助函数 ====================
void TokenizerStateTable_assignCh(TokenizerStateTable* const me, char c) { me->ch = c;}
void TokenizerStateTable_NoNum2GN(TokenizerStateTable* const me, char c) { TokenizerStateTable_assignCh(me, c); me->tensPlace = 10.0;}
void TokenizerStateTable_Frac2Frac(TokenizerStateTable* const me, char c) { me->ch = c; me->result += digit(me->ch) / me->tensPlace; me->tensPlace *= 10;}
void TokenizerStateTable_printResult(TokenizerStateTable* const me) { printf("Number: %g\n", me->result);}
/* * ==================== 状态表模式优势 ==================== * * 1. 清晰的结构: * - 所有状态转换逻辑集中在一个表格中 * - 易于查看和理解整个状态机的行为 * * 2. 易于维护: * - 添加新状态:增加表格的行 * - 添加新事件:增加表格的列 * - 修改转换:只需修改表格单元格 * * 3. 性能优势: * - O(1) 时间复杂度的查表操作 * - 避免了多层嵌套的条件判断 * * 4. 支持高级特性: * - 守卫条件(GuardType) * - 进入/退出/转换动作分离 * - 函数指针实现动态行为 * * 5. 适用场景: * - 中到大型状态机 * - 状态转换规则复杂但规律性强 * - 需要频繁修改状态转换逻辑 */状态模式(State Pattern)
跳转到“状态模式(State Pattern)”抽象 状态模式通过创建状态类对象来实现状态机。每个状态一个,拥有状态机的类称为Context, 维护这些状态对象的列表,通过一个内部变量识别这些状态中的哪一个是当前状态。所有的接收器被看作通过向前动的状态对象。
把状态从‘变量’升级成‘对象’:每个状态都是一个迷你机器人,它自己知道该做什么、下一步该变成谁,Context 只负责把事件交给当前这位机器人,其他一概不管。
1️⃣ 没有状态模式 = 千层 if/switch
switch(state){ case IDLE: if(evt==START) ...; break; case RUN: if(evt==STOP) ...; break;}每加状态、每加事件都要回来翻老巢,代码越来越胖。
2️⃣ 有了状态模式 = 一状态一类/一函数
Context└─ currentState → IdleState::handle() RunState ::handle() StopState::handle()每个状态自带“事件处理 + 状态转换”说明书,Context 只喊一句 current->handle(evt) 就完事。
3️⃣ 在 C 里用函数指针实现“迷你机器人”
状态就是函数指针,事件来了就执行对应函数,函数内部自己把 currentState 换成下一个状态。
问题 该模式一种实现状态机的方法,通过创建对象集合稠化状态空间。其中每一个对象实现单个行为。 它使得状态明确、易于修改,并且能够通过添加新的类容易地为状态机创建新的状态。
模式结构


效果 优势:
- 高度模块化 - 每个状态独立封装
- 符合开闭原则 - 易于添加新状态
- 消除条件语句 - 通过多态替代switch-case
- 状态转换清晰 - 每个状态明确定义可能的转换
劣势:
- 类数量增多 - 每个状态需要一个类
- 内存开销 - 需要创建和维护状态对象
- 性能略低 - 函数指针调用的开销
- 初始化复杂 - 需要创建所有状态对象
实现策略 该模式用C++实现很简单,但是用C实现十分复杂,因为它使用库和多态。在这里显示的 实现中,多态性是通过使用状态的函数指针合成来实现的。首先,所有的状态类实现相同的事件处理接口, 也就是在单个状态类为所有的事件处理程序返回1,如果处理事件的代码涉及多类程序,即使事件被处理, 则聚集件处理程序返回0。这是必要的,因为在Context中需要知道是否该执行它们动作。
示例
/* * 状态模式 - 面向对象的状态机实现 * * 核心思想: * 1. 每个状态是一个独立的类(结构体) * 2. 状态类包含该状态下所有事件的处理方法 * 3. Context类维护当前状态的引用 * 4. 状态转换通过更换Context中的状态对象实现 */
// ==================== StatePattern.h ====================// 代码清单 5-17#ifndef STATEPATTERN_H#define STATEPATTERN_H
#include <stdio.h>#include <stdlib.h>
// 前向声明struct Context;struct Mutex;
// ==================== 状态类型定义 ====================typedef enum TSTATETYPE { NULL_STATE, NONUMBER_STATE, GN_PROCESSINGWHOLEPART_STATE, GN_PROCESSINGFRACTIONALPART_STATE} TSTATETYPE;
// 事件处理函数指针类型typedef int (*ActionPtr0)(void*);typedef int (*ActionPtr1)(void*, char);
// 辅助函数int digit(char c) { return c - '0';}
#endif
// ==================== Context.h ====================// 代码清单 5-18 和 5-19#ifndef CONTEXT_H#define CONTEXT_H
#include "StatePattern.h"
// Context类 - 状态机的上下文typedef struct Context Context;struct Context { // 状态机数据 char ch; TSTATETYPE currentState; double result;
// 关键:持有所有状态类的指针 struct NoNumberState* stateList[GN_PROCESSINGFRACTIONALPART_STATE+1];
double tensPlace; struct Mutex* itsMutex;};
// ==================== Context方法声明 ====================void Context_Init(Context* const me);void Context_Cleanup(Context* const me);Context* Context_Create(void);void Context_Destroy(Context* const me);
// 事件处理方法 - 委托给当前状态对象void Context_evDigit(Context* const me, char c);void Context_evDot(Context* const me);void Context_evEndOfString(Context* const me);void Context_evWhiteSpace(Context* const me);
// 状态管理struct Mutex* Context_getItsMutex(const Context* const me);void Context_setItsMutex(Context* const me, struct Mutex* p_Mutex);
#endif
// ==================== Context.c ====================// 代码清单 5-19#include "Context.h"#include "NoNumberState.h"#include "GN_ProcessingWholeState.h"#include "GN_ProcessingFractionState.h"#include "Mutex.h"
static void cleanUpRelations(Context* const me);
/** * 初始化Context * 创建所有状态对象并存储在stateList数组中 */void Context_Init(Context* const me) { me->ch = 'x'; me->currentState = NULL_STATE; me->result = 0.0; me->tensPlace = 10.0; me->itsMutex = NULL;
// 将stateList初始化为NULL me->stateList[NULL_STATE] = NULL;
/* ===== 关键:创建所有状态对象 ===== */ // 创建NoNumberState me->stateList[NONUMBER_STATE] = NoNumberState_Create(); me->stateList[NONUMBER_STATE]->itsContext = me;
// 创建GN_ProcessingWholeState me->stateList[GN_PROCESSINGWHOLEPART_STATE] = (NoNumberState*)GN_ProcessingWholeState_Create(); me->stateList[GN_PROCESSINGWHOLEPART_STATE]->itsContext = me;
// 创建GN_ProcessingFractionState me->stateList[GN_PROCESSINGFRACTIONALPART_STATE] = (NoNumberState*)GN_ProcessingFractionState_Create(); me->stateList[GN_PROCESSINGFRACTIONALPART_STATE]->itsContext = me;
/* 进入初始状态 */ me->stateList[NONUMBER_STATE]->aSet.entryAction( me->stateList[NONUMBER_STATE]);}
void Context_Cleanup(Context* const me) { // 销毁所有状态对象 NoNumberState_Destroy(me->stateList[NONUMBER_STATE]); GN_ProcessingWholeState_Destroy( (GN_ProcessingWholeState*)me->stateList[GN_PROCESSINGWHOLEPART_STATE]); GN_ProcessingFractionState_Destroy( (GN_ProcessingFractionState*)me->stateList[GN_PROCESSINGFRACTIONALPART_STATE]);
cleanUpRelations(me);}
/** * 处理数字事件 * 核心:委托给当前状态对象处理 */void Context_evDigit(Context* const me, char c) { Mutex_lock(me->itsMutex);
/* 调用当前状态的evDigit处理器 */ /* 这是状态模式的精髓 - 多态调用 */ if (me->stateList[me->currentState] != NULL) { aSet.evDigitHandler(me->stateList[me->currentState], c); } me->stateList[me->currentState]->aSet.evDigitHandler( me->stateList[me->currentState], c);
Mutex_release(me->itsMutex);}
/** * 处理小数点事件 */void Context_evDot(Context* const me) { Mutex_lock(me->itsMutex);
/* 调用当前状态的evDot处理器 */ if (me->stateList[me->currentState] != NULL) { me->stateList[me->currentState]->aSet.evDotHandler( me->stateList[me->currentState]); }
Mutex_release(me->itsMutex);}
/** * 处理字符串结束事件 */void Context_evEndOfString(Context* const me) { Mutex_lock(me->itsMutex);
/* 调用当前状态的evEndOfString处理器 */ if (me->stateList[me->currentState] != NULL) { me->stateList[me->currentState]->aSet.evEOSHandler( me->stateList[me->currentState]); }
Mutex_release(me->itsMutex);}
/** * 处理空白字符事件 */void Context_evWhiteSpace(Context* const me) { Mutex_lock(me->itsMutex);
/* 调用当前状态的evWhiteSpace处理器 */ if (me->stateList[me->currentState] != NULL) { me->stateList[me->currentState]->aSet.evWSHandler( me->stateList[me->currentState]); }
Mutex_release(me->itsMutex);}
// ==================== StateActionSet.h ====================// 代码清单 5-20#ifndef STATEACTIONSET_H#define STATEACTIONSET_H
#include "StatePattern.h"
/** * StateActionSet - 状态动作集 * 每个状态类都包含这个结构,定义了该状态下所有可能的动作 */typedef struct StateActionSet StateActionSet;struct StateActionSet { ActionPtr0 entryAction; // 进入动作 ActionPtr1 evDigitHandler; // 数字事件处理器 ActionPtr0 evDotHandler; // 小数点事件处理器 ActionPtr0 evEOSHandler; // 字符串结束事件处理器 ActionPtr0 evWSHandler; // 空白字符事件处理器 ActionPtr0 exitAction; // 退出动作};
// 构造和析构void StateActionSet_Init(StateActionSet* const me);void StateActionSet_Cleanup(StateActionSet* const me);StateActionSet* StateActionSet_Create(void);void StateActionSet_Destroy(StateActionSet* const me);
#endif
// ==================== StateActionSet.c ====================// 代码清单 5-21#include "StateActionSet.h"
void StateActionSet_Init(StateActionSet* const me) { me->entryAction = NULL; me->evDigitHandler = NULL; me->evDotHandler = NULL; me->evEOSHandler = NULL; me->evWSHandler = NULL; me->exitAction = NULL;}
void StateActionSet_Cleanup(StateActionSet* const me) { // 清理(如果需要)}
StateActionSet* StateActionSet_Create(void) { StateActionSet* me = (StateActionSet*)malloc(sizeof(StateActionSet)); if(me != NULL) { StateActionSet_Init(me); } return me;}
void StateActionSet_Destroy(StateActionSet* const me) { if(me != NULL) { StateActionSet_Cleanup(me); free(me); }}
// ==================== NoNumberState.h ====================// 代码清单 5-22#ifndef NONUMBERSTATE_H#define NONUMBERSTATE_H
#include "StatePattern.h"#include "StateActionSet.h"#include "Context.h"
/** * NoNumberState - 无数字状态类 * 这是状态模式的关键:每个状态是一个独立的类 */struct Context;typedef struct NoNumberState NoNumberState;struct NoNumberState { struct StateActionSet aSet; // 动作集 struct Context* itsContext; // 关联的Context};
// 构造和析构void NoNumberState_Init(NoNumberState* const me);void NoNumberState_Cleanup(NoNumberState* const me);NoNumberState* NoNumberState_Create(void);void NoNumberState_Destroy(NoNumberState* const me);
// 事件处理方法void NoNumberState_NoNum2GN(NoNumberState* const me, char c);void NoNumberState_entryAction(NoNumberState* const me);int NoNumberState_evDigit(NoNumberState* const me, char c);int NoNumberState_evDot(NoNumberState* const me);int NoNumberState_evEndOfString(NoNumberState* const me);int NoNumberState_evWhiteSpace(NoNumberState* const me);void NoNumberState_exitAction(NoNumberState* const me);
// Context关联struct Context* NoNumberState_getItsContext(const NoNumberState* const me);void NoNumberState_setItsContext(NoNumberState* const me, struct Context* p_Context);
#endif
// ==================== NoNumberState.c ====================// 代码清单 5-23#include "NoNumberState.h"#include "Context.h"#include <stdio.h>
static void cleanUpRelations(NoNumberState* const me);
void NoNumberState_Init(NoNumberState* const me) { StateActionSet_Init(&me->aSet);
me->itsContext = NULL;
/* 设置该状态的动作函数指针 */ /* 记住这是初始化StateActionSet的指针 */ /* 设置所有指向NULL作为默认值 */ me->aSet.evDigitHandler = (ActionPtr1)NoNumberState_evDigit; me->aSet.evDotHandler = (ActionPtr0)NoNumberState_evDot; me->aSet.evWSHandler = (ActionPtr0)NoNumberState_evWhiteSpace; me->aSet.evEOSHandler = (ActionPtr0)NoNumberState_evEndOfString; me->aSet.entryAction = (ActionPtr0)NoNumberState_entryAction; me->aSet.exitAction = (ActionPtr0)NoNumberState_exitAction;}
void NoNumberState_Cleanup(NoNumberState* const me) { cleanUpRelations(me);}
void NoNumberState_NoNum2GN(NoNumberState* const me, char c) { me->itsContext->ch = c; me->itsContext->tensPlace = 10.0;}
void NoNumberState_entryAction(NoNumberState* const me) { me->itsContext->result = 0.0;}
/** * NoNumberState处理数字事件 * 转换到GN_PROCESSINGWHOLEPART_STATE */int NoNumberState_evDigit(NoNumberState* const me, char c) { NoNumberState_exitAction(me); NoNumberState_NoNum2GN(me, c); /* 转换动作 */
/* 关键:设置新状态 */ me->itsContext->currentState = GN_PROCESSINGWHOLEPART_STATE; return 1; /* 处理了事件 */}
/** * NoNumberState处理小数点事件 * 转换到GN_PROCESSINGFRACTIONALPART_STATE */int NoNumberState_evDot(NoNumberState* const me) { return 0; /* 未处理事件 */}
int NoNumberState_evEndOfString(NoNumberState* const me) { return 0; /* 未处理事件 */}
int NoNumberState_evWhiteSpace(NoNumberState* const me) { return 0; /* 未处理事件 */}
void NoNumberState_exitAction(NoNumberState* const me) { /* 退出动作(如果需要) */}
struct Context* NoNumberState_getItsContext(const NoNumberState* const me) { return (struct Context*)me->itsContext;}
void NoNumberState_setItsContext(NoNumberState* const me, struct Context* p_Context) { me->itsContext = p_Context;}
NoNumberState* NoNumberState_Create(void) { NoNumberState* me = (NoNumberState*)malloc(sizeof(NoNumberState)); if(me != NULL) { NoNumberState_Init(me); } return me;}
void NoNumberState_Destroy(NoNumberState* const me) { if(me != NULL) { NoNumberState_Cleanup(me); free(me); }}
static void cleanUpRelations(NoNumberState* const me) { if(me->itsContext != NULL) { me->itsContext = NULL; }}
// ==================== GN_ProcessingWholeState.h ====================// 代码清单 5-24#ifndef GN_PROCESSINGWHOLESTATE_H#define GN_PROCESSINGWHOLESTATE_H
#include "StatePattern.h"#include "StateActionSet.h"
struct Context;
/** * GN_ProcessingWholeState - 处理整数部分状态 * 继承自NoNumberState(在C中通过组合实现) */typedef struct GN_ProcessingWholeState GN_ProcessingWholeState;struct GN_ProcessingWholeState { struct StateActionSet aSet; struct Context* itsContext;};
// 方法声明void GN_ProcessingWholeState_Init(GN_ProcessingWholeState* const me);void GN_ProcessingWholeState_Cleanup(GN_ProcessingWholeState* const me);GN_ProcessingWholeState* GN_ProcessingWholeState_Create(void);void GN_ProcessingWholeState_Destroy(GN_ProcessingWholeState* const me);
// 事件处理void GN_ProcessingWholeState_entryAction(GN_ProcessingWholeState* const me);int GN_ProcessingWholeState_evDigit(GN_ProcessingWholeState* const me, char c);int GN_ProcessingWholeState_evDot(GN_ProcessingWholeState* const me);int GN_ProcessingWholeState_evEndOfString(GN_ProcessingWholeState* const me);int GN_ProcessingWholeState_evWhiteSpace(GN_ProcessingWholeState* const me);void GN_ProcessingWholeState_exitAction(GN_ProcessingWholeState* const me);void GN_ProcessingWholeState_printResult(GN_ProcessingWholeState* const me);
// Context关联struct Context* GN_ProcessingWholeState_getItsContext(const GN_ProcessingWholeState* const me);void GN_ProcessingWholeState_setItsContext(GN_ProcessingWholeState* const me, struct Context* p_Context);
#endif
// ==================== GN_ProcessingWholeState.c ====================// 代码清单 5-25#include "GN_ProcessingWholeState.h"#include "Context.h"#include <stdio.h>
static void cleanUpRelations(GN_ProcessingWholeState* const me);
void GN_ProcessingWholeState_Init(GN_ProcessingWholeState* const me) { StateActionSet_Init(&me->aSet); me->itsContext = NULL;
/* 设置该状态的动作函数指针 */ /* 记住这是初始化StateActionSet的指针 */ /* 设置所有指针为NULL作为默认值 */ me->aSet.evDigitHandler = (ActionPtr1)GN_ProcessingWholeState_evDigit; me->aSet.evDotHandler = (ActionPtr0)GN_ProcessingWholeState_evDot; me->aSet.evWSHandler = (ActionPtr0)GN_ProcessingWholeState_evWhiteSpace; me->aSet.evEOSHandler = (ActionPtr0)GN_ProcessingWholeState_evEndOfString; me->aSet.entryAction = (ActionPtr0)GN_ProcessingWholeState_entryAction; me->aSet.exitAction = (ActionPtr0)GN_ProcessingWholeState_exitAction;}
void GN_ProcessingWholeState_Cleanup(GN_ProcessingWholeState* const me) { cleanUpRelations(me);}
void GN_ProcessingWholeState_entryAction(GN_ProcessingWholeState* const me) { me->itsContext->result = me->itsContext->result * 10 + digit(me->itsContext->ch);}
/** * 处理数字事件 - 保持在当前状态 * 注意:与其他模式不同,这里不需要改变itsContext->currentState */int GN_ProcessingWholeState_evDigit(GN_ProcessingWholeState* const me, char c) { GN_ProcessingWholeState_exitAction(me); me->itsContext->ch = c; /* 转换动作 */ /* 注意:状态保持不变,所以是同一状态 */ /* 因此无需改变itsContext->currentState */ return 1; /* 事件已处理 */}
/** * 处理小数点事件 - 转换到小数处理状态 */int GN_ProcessingWholeState_evDot(GN_ProcessingWholeState* const me) { GN_ProcessingWholeState_exitAction(me); /* 无转换动作 */ me->itsContext->currentState = GN_PROCESSINGFRACTIONALPART_STATE; return 1; /* 事件已处理 */}
/** * 处理字符串结束事件 - 返回无数字状态 */int GN_ProcessingWholeState_evEndOfString(GN_ProcessingWholeState* const me) { GN_ProcessingWholeState_exitAction(me); GN_ProcessingWholeState_printResult(me); /* 转换动作 */ me->itsContext->currentState = NONUMBER_STATE; return 1; /* 事件已处理 */}
int GN_ProcessingWholeState_evWhiteSpace(GN_ProcessingWholeState* const me) { GN_ProcessingWholeState_exitAction(me); GN_ProcessingWholeState_printResult(me); /* 转换动作 */ me->itsContext->currentState = NONUMBER_STATE; return 1; /* 事件已处理 */}
/* 操作exitAction() */void GN_ProcessingWholeState_exitAction(GN_ProcessingWholeState* const me) { /* 退出动作(如果需要) */}
void GN_ProcessingWholeState_printResult(GN_ProcessingWholeState* const me) { printf("Number: %g\n", me->itsContext->result);}
struct Context* GN_ProcessingWholeState_getItsContext(const GN_ProcessingWholeState* const me) { return (struct Context*)me->itsContext;}
void GN_ProcessingWholeState_setItsContext(GN_ProcessingWholeState* const me, struct Context* p_Context) { me->itsContext = p_Context;}
GN_ProcessingWholeState* GN_ProcessingWholeState_Create(void) { GN_ProcessingWholeState* me = (GN_ProcessingWholeState*) malloc(sizeof(GN_ProcessingWholeState)); if(me != NULL) { GN_ProcessingWholeState_Init(me); } return me;}
void GN_ProcessingWholeState_Destroy(GN_ProcessingWholeState* const me) { if(me != NULL) { GN_ProcessingWholeState_Cleanup(me); free(me); }}
static void cleanUpRelations(GN_ProcessingWholeState* const me) { if(me->itsContext != NULL) { me->itsContext = NULL; }}
// ==================== GN_ProcessingFractionState 类似实现 ====================// 代码清单 5-26 和 5-27// [由于篇幅原因,GN_ProcessingFractionState的实现与GN_ProcessingWholeState类似]
/* * ==================== 状态模式总结 ==================== * * 优势: * 1. 高度模块化 - 每个状态是独立的类,易于理解和维护 * 2. 符合开闭原则 - 添加新状态只需添加新类,不修改现有代码 * 3. 消除条件语句 - 通过多态替代switch-case * 4. 状态转换清晰 - 每个状态类明确定义了可能的转换 * * 劣势: * 1. 类数量增多 - 每个状态需要一个类 * 2. 内存开销 - 需要创建和维护多个状态对象 * 3. 性能略低 - 虚函数调用的开销(在C中是函数指针) * * 适用场景: * - 状态行为差异很大 * - 需要频繁添加新状态 * - 团队熟悉面向对象设计 * - 代码可维护性比性能更重要 */与状态(AND States)
跳转到“与状态(AND States)”与状态(AND States),也称为并发状态(Concurrent States)或正交状态(Orthogonal States),是指系统可以同时处于多个状态的情况。
模式结构


示例
// ============================================// 竞争条件问题 - 基于教材图5-21和5-22// ============================================
/** * 图5-21展示的问题:事件e1触发时的竞争条件 * * 初始状态:x = 1 * 四个并发状态同时处理事件e1 */
// ============================================// 场景1:理想的顺序执行// ============================================class IdealSequentialExecution { constructor() { this.x = 1; console.log('=== 理想顺序执行 ==='); console.log('初始: x =', this.x); }
execute() { // State_1 处理 e1 console.log('\nState_1 处理 e1:'); console.log(' 执行: x = x * 10'); this.x = this.x * 10; console.log(' 结果: x =', this.x);
// State_2 处理 e1 console.log('\nState_2 处理 e1:'); console.log(' 执行: GEN(e2) - 生成事件e2'); console.log(' 此时看到的x =', this.x);
// State_3 等待 e2 console.log('\nState_3 等待事件 e2...');
// State_4 等待 e2 console.log('State_4 等待事件 e2...');
console.log('\n最终结果: x =', this.x); return this.x; }}
// ============================================// 场景2:有问题的并发执行(竞争条件)// ============================================class ProblematicConcurrentExecution { constructor() { this.x = 1; this.events = []; console.log('\n=== 有问题的并发执行 ==='); console.log('初始: x =', this.x); }
async execute() { // 所有状态同时读取x的值 const initialX = this.x; console.log('\n所有状态同时读取 x =', initialX);
// 并发执行(模拟竞争) const state1 = this.state1Action(initialX); const state2 = this.state2Action(initialX); const state3 = this.state3Action(); const state4 = this.state4Action();
// 等待所有操作完成 await Promise.all([state1, state2, state3, state4]);
console.log('\n⚠️ 问题:最终的x值不确定!'); console.log('可能的结果:'); console.log(' - 如果State_1最后写入: x = 10'); console.log(' - 如果其他状态覆盖: x = ?'); console.log('实际结果: x =', this.x);
return this.x; }
async state1Action(readValue) { // 模拟处理延迟 await this.delay(Math.random() * 100);
console.log('State_1: 读取 x =', readValue, ', 计算 x * 10 =', readValue * 10);
// 竞争写入 this.x = readValue * 10; }
async state2Action(readValue) { await this.delay(Math.random() * 100);
console.log('State_2: 读取 x =', readValue, ', 生成事件 e2'); this.events.push('e2');
// State_2 可能也会修改x(根据具体实现) // 这里展示了不确定性 }
async state3Action() { await this.delay(Math.random() * 100); console.log('State_3: 等待事件 e2'); }
async state4Action() { await this.delay(Math.random() * 100); console.log('State_4: 等待事件 e2'); }
delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }}
// ============================================// 场景3:图5-22的事件传播问题// ============================================class EventPropagationProblem { constructor() { this.x = 1; console.log('\n=== 事件传播问题(图5-22)==='); }
demonstrate() { console.log('初始: x =', this.x);
// 第一种情况:e1先完全处理,然后e2 console.log('\n情况1:e1完全处理后,e2才开始'); let x1 = 1; x1 = x1 * 10; // State_1: e1/x*=10 console.log(' e1处理后: x =', x1); // GEN(e2) x1 = x1 + 3; // State_3: e2/x+=3 console.log(' e2处理后: x =', x1, '✓ 结果确定');
// 第二种情况:e2在e1处理中生成 console.log('\n情况2:e2在e1处理过程中生成'); let x2 = 1; // State_2 生成 e2,但此时 State_1 还没处理完 console.log(' State_2 生成e2时: x =', x2); console.log(' State_3 处理e2: x + 3 =', x2 + 3); x2 = x2 + 3; // State_3 先执行 x2 = x2 * 10; // State_1 后执行 console.log(' 最终: x =', x2, '✗ 错误的结果!');
return { case1: x1, case2: x2 }; }}
// ============================================// 解决方案实现// ============================================
/** * 解决方案1:事件队列(Event Queue) */class EventQueueSolution { constructor() { this.x = 1; this.eventQueue = []; this.processing = false; }
async handleEvent(event) { console.log(`\n添加事件 ${event} 到队列`); this.eventQueue.push(event);
if (!this.processing) { await this.processQueue(); } }
async processQueue() { this.processing = true;
while (this.eventQueue.length > 0) { const event = this.eventQueue.shift(); console.log(`处理事件: ${event}`);
// 顺序处理,避免竞争 if (event === 'e1') { this.x *= 10; console.log(` x *= 10, 结果: x = ${this.x}`); // 生成 e2 this.eventQueue.push('e2'); } else if (event === 'e2') { this.x += 3; console.log(` x += 3, 结果: x = ${this.x}`); } }
this.processing = false; }}
/** * 解决方案2:互斥锁(Mutex) */class MutexSolution { constructor() { this.x = 1; this.locked = false; this.waitQueue = []; }
async acquire() { while (this.locked) { await new Promise(resolve => { this.waitQueue.push(resolve); }); } this.locked = true; console.log(' 获取锁'); }
release() { this.locked = false; console.log(' 释放锁');
if (this.waitQueue.length > 0) { const resolve = this.waitQueue.shift(); resolve(); } }
async modifyX(operation, value) { await this.acquire(); try { const oldX = this.x;
if (operation === 'multiply') { this.x *= value; console.log(` 临界区: x从${oldX}变为${this.x} (×${value})`); } else if (operation === 'add') { this.x += value; console.log(` 临界区: x从${oldX}变为${this.x} (+${value})`); } } finally { this.release(); } }}
/** * 解决方案3:原子操作(Atomic Operations) */class AtomicOperationsSolution { constructor() { // 使用 SharedArrayBuffer 和 Atomics(简化示例) this.buffer = new SharedArrayBuffer(4); this.x = new Int32Array(this.buffer); Atomics.store(this.x, 0, 1); // 初始值为1 }
atomicMultiply(factor) { let oldValue, newValue; do { oldValue = Atomics.load(this.x, 0); newValue = oldValue * factor; } while (Atomics.compareExchange(this.x, 0, oldValue, newValue) !== oldValue);
console.log(`原子操作: ${oldValue} → ${newValue} (×${factor})`); return newValue; }
atomicAdd(value) { const result = Atomics.add(this.x, 0, value); console.log(`原子操作: ${result} → ${result + value} (+${value})`); return result + value; }}
/** * 解决方案4:Actor模型(Message Passing) */class ActorModelSolution { constructor() { this.actors = { state1: new StateActor('State1'), state2: new StateActor('State2'), state3: new StateActor('State3'), state4: new StateActor('State4'), coordinator: new CoordinatorActor() }; }
async sendMessage(to, message) { console.log(`发送消息 [${message.type}] 到 ${to}`); await this.actors[to].receive(message); }}
class StateActor { constructor(name) { this.name = name; this.mailbox = []; this.localX = 1; // 每个Actor有自己的本地状态 }
async receive(message) { this.mailbox.push(message); await this.processMessages(); }
async processMessages() { while (this.mailbox.length > 0) { const msg = this.mailbox.shift(); console.log(` ${this.name} 处理消息:`, msg);
switch (msg.type) { case 'e1': if (this.name === 'State1') { this.localX *= 10; // 发送更新消息给协调器 } else if (this.name === 'State2') { // 生成 e2 消息 } break; case 'e2': if (this.name === 'State3') { this.localX += 3; } break; } } }}
class CoordinatorActor { constructor() { this.globalX = 1; this.pendingUpdates = []; }
async receive(message) { if (message.type === 'update') { // 协调所有状态更新 this.pendingUpdates.push(message); await this.reconcile(); } }
async reconcile() { // 按顺序应用所有更新 for (const update of this.pendingUpdates) { console.log(' 协调器应用更新:', update); this.globalX = update.value; } this.pendingUpdates = []; }}
// ============================================// 测试和演示// ============================================
async function demonstrateRaceConditions() { console.log('╔══════════════════════════════════════════╗'); console.log('║ 竞争条件问题演示(基于图5-21, 5-22) ║'); console.log('╚══════════════════════════════════════════╝');
// 1. 理想顺序执行 const ideal = new IdealSequentialExecution(); ideal.execute();
// 2. 有问题的并发执行 const problematic = new ProblematicConcurrentExecution(); await problematic.execute();
// 3. 事件传播问题 const propagation = new EventPropagationProblem(); propagation.demonstrate();
console.log('\n╔══════════════════════════════════════════╗'); console.log('║ 解决方案演示 ║'); console.log('╚══════════════════════════════════════════╝');
// 解决方案1:事件队列 console.log('\n=== 解决方案1:事件队列 ==='); const queue = new EventQueueSolution(); await queue.handleEvent('e1'); console.log('最终结果: x =', queue.x);
// 解决方案2:互斥锁 console.log('\n=== 解决方案2:互斥锁 ==='); const mutex = new MutexSolution(); await Promise.all([ mutex.modifyX('multiply', 10), mutex.modifyX('add', 3) ]); console.log('最终结果: x =', mutex.x);
// 解决方案3:原子操作 console.log('\n=== 解决方案3:原子操作 ==='); const atomic = new AtomicOperationsSolution(); atomic.atomicMultiply(10); atomic.atomicAdd(3); console.log('最终结果: x =', Atomics.load(atomic.x, 0));
// 解决方案4:Actor模型 console.log('\n=== 解决方案4:Actor模型 ==='); const actors = new ActorModelSolution(); await actors.sendMessage('state1', { type: 'e1' }); await actors.sendMessage('state2', { type: 'e1' }); console.log('Actor模型通过消息传递避免共享状态');}
// 执行演示demonstrateRaceConditions();分解与状态模式
跳转到“分解与状态模式”该模式扩展状态模式实现与状态。它通过创建不同对象的协作来完成,其中的每一个分配一个与状态。
分解与状态模式”就是把一个又大又乱的状态机拆成多个小状态机,每个小机器只管自己的一摊子事(正交区域),然后大家一起协作,主机器只负责“搭台子”。
1️⃣ 没拆分前
一个洗衣机状态机:├─洗涤状态├─脱水状态├─烘干状态└─门锁状态所有逻辑挤在一起 → 状态爆炸、维护困难。
2️⃣ 拆分后
主洗衣机(全局状态)├─洗涤子机(只关心洗涤)├─脱水子机(只关心脱水)├─烘干子机(只关心烘干)└─门锁子机(只关心门锁)每个子机只处理自己的状态;主洗衣机只协调“谁在干活”。
抽象 分解与状态模式带有拥有状态机的对象,并且将它分解为一组交互的对象。主要的对象拥有全局状态机,并且其他的对象拥有各自的与状态。
问题 该模式以一种保护与状态设计的方式包含正交区域(与状态)解决状态机的实现问题。
模式结构

示例
// ============================================// 1. 基础结构定义// ============================================
// 灯光控制器的数据结构struct Klaxon { // Klaxon是警报器的意思};
struct Light { // Light代表指示灯};
struct Mutex { // 互斥锁,用于线程安全};
// ============================================// 2. 抽象AND状态基类// ============================================
/** * AbstractAndStateClass * 这是分解状态模式的核心抽象基类 * 每个具体的AND状态都要继承这个类 */class AbstractAndStateClass {public: // 虚析构函数,确保派生类正确析构 virtual ~AbstractAndStateClass() {}
// 纯虚函数:处理事件 // 参数:事件类型 // 返回:处理后的新状态(如果状态不变则返回this) virtual AbstractAndStateClass* event1() = 0; virtual AbstractAndStateClass* event2() = 0; // ... 其他事件处理函数};
// ============================================// 3. 具体AND状态类// ============================================
/** * ConcreteAndStateClass * 具体的AND状态实现类 * 每个类代表一个具体的原子状态 */class ConcreteAndStateClass : public AbstractAndStateClass {private: // 指向Context的指针,用于访问共享资源 Context* context_;
public: // 构造函数 ConcreteAndStateClass(Context* ctx) : context_(ctx) {}
// 实现事件处理 virtual AbstractAndStateClass* event1() override { // 处理event1 // 可能的动作: // 1. 执行某些操作 // 2. 返回新状态或this(保持当前状态) return this; }
virtual AbstractAndStateClass* event2() override { // 处理event2 return new AnotherConcreteAndStateClass(context_); }};
// ============================================// 4. Context类 - 管理所有并发状态域// ============================================
/** * Context类 * 这是整个状态机的核心管理器 * 它维护多个正交的状态域 */class Context {private: // 维护多个并发的状态域 // 每个状态域独立变化 AbstractAndStateClass* stateRegion1_; // 状态域1 AbstractAndStateClass* stateRegion2_; // 状态域2 // ... 可以有更多状态域
public: // 构造函数:初始化所有状态域 Context() { stateRegion1_ = new InitialState1(this); stateRegion2_ = new InitialState2(this); }
// 析构函数:清理所有状态 ~Context() { delete stateRegion1_; delete stateRegion2_; }
// 事件分发函数 // 将事件广播到所有状态域 void handleEvent1() { // 关键:同时更新多个状态域 AbstractAndStateClass* newState1 = stateRegion1_->event1(); if (newState1 != stateRegion1_) { delete stateRegion1_; stateRegion1_ = newState1; }
AbstractAndStateClass* newState2 = stateRegion2_->event1(); if (newState2 != stateRegion2_) { delete stateRegion2_; stateRegion2_ = newState2; } }};
// ============================================// 5. LightController 完整实现// ============================================
// 状态枚举定义typedef enum HighLevelLightStates { NULL_STATE, OFF_STATE, ON_STATE, EMERGENCY_STATE} HighLevelLightStates;
typedef enum ColorType { RED, YELLOW, GREEN} ColorType;
typedef enum FlashType { STEADY, // 稳定(持续亮) SLOWLY, // 缓慢闪烁 QUICKLY // 快速闪烁} FlashType;
typedef enum ErrorStatesType { NULL_ERROR_STATE, OK_STATE, WARNING_STATE, ERROR_STATE} ErrorStatesType;
typedef enum ModeStatesType { NULL_MODE_STATE, OPERATIONAL_STATE, STARTINGUP_STATE, SHUTTINGDOWN_STATE} ModeStatesType;
// 前向声明class LightController;class AndStateList;class ErrorStateClass;class ModeStateClass;
// ============================================// 5.1 AndStateList - AND状态列表管理器// ============================================
/** * AndStateList * 管理所有AND状态(并发状态域)的容器 * 它维护着同时活跃的多个正交状态 */class AndStateList {private: // 最多支持MAX_ANDSTATES个并发状态域 #define MAX_ANDSTATES 2
// 状态数组:保存所有活跃的AND状态 ErrorStateClass* andStates[MAX_ANDSTATES]; int nAndStates; // 当前活跃状态数
public: // 构造函数:初始化为空 AndStateList() { nAndStates = 0; for (int j = 0; j < MAX_ANDSTATES; j++) { andStates[j] = NULL; } }
// 创建并初始化所有AND状态 void Create(LightController* lc);
// 清理所有状态 void Cleanup() { for (int i = 0; i < nAndStates; i++) { if (andStates[i]) { delete andStates[i]; andStates[i] = NULL; } } nAndStates = 0; }
// 析构函数 ~AndStateList() { Cleanup(); }
// 初始化所有状态到初始状态 void Init();
// 事件处理函数 - 广播到所有AND状态 void entryAction(); void exitAction();
// 将事件广播到所有嵌套的AND状态 void enterNestedAndStates(HighLevelLightStates next); void exitNestedAndStates(); void enterOffState(); void enterOnState(); void enterEmergencyState(); void exitOffState(); void exitOnState(); void exitEmergencyState();
// 具体事件处理 void evEnable(); void evDisable(); void evAbort(); void evError(); void evWarning(); void evOk(); void evRun(); void evShutDown();};
// ============================================// 5.2 StateActionSet - 状态动作集合// ============================================
/** * StateActionSet * 封装每个状态需要执行的动作 * 这是命令模式的应用,将动作和状态解耦 */class StateActionSet {private: // 各种动作处理器的函数指针 typedef void (*ActionPtr)();
ActionPtr entryAction_; // 进入动作 ActionPtr evAbortHandler_; // abort事件处理 ActionPtr evDisableHandler_; // disable事件处理 ActionPtr evEnableHandler_; // enable事件处理 ActionPtr evErrorHandler_; // error事件处理 ActionPtr evOkHandler_; // ok事件处理 ActionPtr evRunHandler_; // run事件处理 ActionPtr evShutDownHandler_;// shutdown事件处理 ActionPtr evWarningHandler_; // warning事件处理 ActionPtr exitAction_; // 退出动作 ActionPtr is_inHandler_; // 状态查询处理
public: // 构造函数:初始化所有处理器为NULL StateActionSet() { entryAction_ = NULL; evAbortHandler_ = NULL; evDisableHandler_ = NULL; evEnableHandler_ = NULL; evErrorHandler_ = NULL; evOkHandler_ = NULL; evRunHandler_ = NULL; evShutDownHandler_ = NULL; evWarningHandler_ = NULL; exitAction_ = NULL; is_inHandler_ = NULL; }
// 清理函数 void Cleanup() { // 将所有函数指针重置为NULL }
// 初始化函数:设置具体的动作处理器 void Init(/* 参数列表 */);};
// ============================================// 5.3 ErrorStateClass - 错误状态基类// ============================================
/** * ErrorStateClass * 错误状态域的基类 * 管理 OK/Warning/Error 三种错误状态 */class ErrorStateClass {protected: LightController* itsLightController_; // 指向控制器
public: // 构造函数 ErrorStateClass(LightController* lc) : itsLightController_(lc) {}
// 虚析构函数 virtual ~ErrorStateClass() {}
// 纯虚函数:处理各种事件 virtual void Init() = 0; virtual void Cleanup() = 0; virtual void entryAction() = 0; virtual void evAbort() = 0; virtual void evError() = 0; virtual void evOk() = 0; virtual void evWarning() = 0; virtual void exitAction() = 0; virtual ErrorStateClass* is_in(ErrorStatesType s) = 0;};
// 具体错误状态类class ErrorState : public ErrorStateClass {public: ErrorState(LightController* lc) : ErrorStateClass(lc) {}
virtual void entryAction() override { // 进入错误状态:设置红灯 setLightColor(RED); }
virtual void evOk() override { // 收到OK事件:转换到OK状态 changeToOkState(); }
// ... 其他事件处理};
// ============================================// 5.4 ModeStateClass - 运行模式基类// ============================================
/** * ModeStateClass * 运行模式状态域的基类 * 管理 StartingUp/Operational/ShuttingDown 三种运行模式 */class ModeStateClass {protected: LightController* itsLightController_;
public: ModeStateClass(LightController* lc) : itsLightController_(lc) {}
virtual ~ModeStateClass() {}
// 纯虚函数:处理各种事件 virtual void Init() = 0; virtual void Cleanup() = 0; virtual void entryAction() = 0; virtual void evRun() = 0; virtual void evShutDown() = 0; virtual void exitAction() = 0; virtual ModeStateClass* is_in(ModeStatesType s) = 0;};
// ============================================// 5.5 LightController - 主控制器// ============================================
/** * LightController * 灯光控制器主类 * 这是整个状态机的Context,管理所有状态域 */class LightController {private: // 高层状态 HighLevelLightStates currentState_;
// AND状态列表(管理并发状态域) AndStateList* asList_;
// 硬件资源 Klaxon* itsKlaxon_; Light* itsLight_; Mutex* itsMutex_;
public: // 构造函数 LightController() { currentState_ = OFF_STATE; asList_ = new AndStateList(); itsKlaxon_ = new Klaxon(); itsLight_ = new Light(); itsMutex_ = new Mutex();
// 初始化AND状态 Init(); }
// 析构函数 ~LightController() { Cleanup(); delete asList_; delete itsKlaxon_; delete itsLight_; delete itsMutex_; }
// 初始化函数 void Init() { currentState_ = OFF_STATE; // 进入初始状态 enter_OffState(OFF_STATE);
// 创建所有AND状态(如果需要) if (currentState_ == ON_STATE) { // 在ON状态下,创建并初始化所有并发状态域 asList_->Create(this);
// 初始化每个状态域到其默认状态 // ErrorStatus域 -> OK_STATE // Mode域 -> STARTINGUP_STATE for (int i = 0; i < asList_->nAndStates; i++) { asList_->andStates[i]->Init(); } } }
// ======================================== // 事件处理函数 // ========================================
/** * evEnable - 启用事件 * 将系统从OFF状态转换到ON状态 */ void evEnable() { HighLevelLightStates newState;
Mutex_lock(itsMutex_); // 加锁,确保线程安全
switch (currentState_) { case OFF_STATE: // 退出当前状态 exit_OffState();
// 转换到ON状态 newState = ON_STATE; LightController_exit_OffState(this);
// 进入新状态 LightController_enter_OnState(this, newState); currentState_ = newState; break;
case ON_STATE: case EMERGENCY_STATE: // 在这些状态下忽略enable事件 break; }
Mutex_release(itsMutex_); // 解锁 }
/** * evDisable - 禁用事件 * 将系统从ON状态转换回OFF状态 */ void evDisable() { HighLevelLightStates newState;
Mutex_lock(itsMutex_);
switch (currentState_) { case ON_STATE: // 先退出所有嵌套的AND状态 asList_->exitNestedAndStates();
// 退出ON状态 exit_OnState();
// 转换到OFF状态 newState = OFF_STATE; LightController_exit_OnState(this); LightController_enter_OffState(this, newState); currentState_ = newState; break;
case OFF_STATE: case EMERGENCY_STATE: // 忽略 break; }
Mutex_release(itsMutex_); }
/** * evAbort - 中止事件 * 紧急情况,立即转到EMERGENCY_STATE */ void evAbort() { HighLevelLightStates newState;
Mutex_lock(itsMutex_);
// 无论当前在什么状态,都转到紧急状态 switch (currentState_) { case OFF_STATE: exit_OffState(); newState = EMERGENCY_STATE; enter_EmergencyState(newState); currentState_ = newState; break;
case ON_STATE: // 先清理AND状态 asList_->exitNestedAndStates(); exit_OnState(); newState = EMERGENCY_STATE; enter_EmergencyState(newState); currentState_ = newState; break;
case EMERGENCY_STATE: // 已经在紧急状态,不做处理 break; }
Mutex_release(itsMutex_); }
/** * evError - 错误事件 * 将错误状态域转换到ERROR状态 */ void evError() { Mutex_lock(itsMutex_);
if (currentState_ == ON_STATE) { // 将事件委托给AND状态处理 asList_->evError(); }
Mutex_release(itsMutex_); }
/** * evWarning - 警告事件 */ void evWarning() { Mutex_lock(itsMutex_);
if (currentState_ == ON_STATE) { asList_->evWarning(); }
Mutex_release(itsMutex_); }
/** * evOk - OK事件 * 清除错误/警告状态 */ void evOk() { Mutex_lock(itsMutex_);
if (currentState_ == ON_STATE) { asList_->evOk(); }
Mutex_release(itsMutex_); }
/** * evRun - 运行事件 * 将模式状态域转换到OPERATIONAL状态 */ void evRun() { Mutex_lock(itsMutex_);
if (currentState_ == ON_STATE) { asList_->evRun(); }
Mutex_release(itsMutex_); }
/** * evShutDown - 关闭事件 * 将模式状态域转换到SHUTTINGDOWN状态 */ void evShutDown() { Mutex_lock(itsMutex_);
if (currentState_ == ON_STATE) { asList_->evShutDown(); }
Mutex_release(itsMutex_); }
/** * reset - 重置事件 * 从EMERGENCY_STATE返回到OFF_STATE */ void reset() { Mutex_lock(itsMutex_);
if (currentState_ == EMERGENCY_STATE) { exit_EmergencyState(); currentState_ = OFF_STATE; enter_OffState(OFF_STATE); }
Mutex_release(itsMutex_); }
// ======================================== // 辅助函数 // ========================================
// 设置灯光颜色 void setLightColor(ColorType color) { // 实际的硬件控制代码 itsLight_->setColor(color); }
// 设置闪烁模式 void setFlashMode(FlashType mode) { // 实际的硬件控制代码 itsLight_->setMode(mode); }
// 控制警报器 void alarmOn() { itsKlaxon_->on(); }
void alarmOff() { itsKlaxon_->off(); }};
// ============================================// 6. AndStateList 实现细节// ============================================
void AndStateList::Create(LightController* lc) { // 创建两个并发状态域
// 1. 错误状态域(ErrorStatus) andStates[0] = new ErrorStateClass_Create(lc);
// 2. 运行模式域(Mode) andStates[1] = new ModeStateClass_Create(lc);
nAndStates = 2;}
void AndStateList::Init() { // 初始化所有AND状态到其默认状态 for (int i = 0; i < nAndStates; i++) { if (andStates[i]) { andStates[i]->Init(); } }}
void AndStateList::evError() { // 将错误事件广播到所有状态域 // 只有ErrorStateClass会响应这个事件 for (int i = 0; i < nAndStates; i++) { if (andStates[i]) { andStates[i]->evError(); } }}
void AndStateList::evRun() { // 将运行事件广播到所有状态域 // 只有ModeStateClass会响应这个事件 for (int i = 0; i < nAndStates; i++) { if (andStates[i]) { andStates[i]->evRun(); } }}
// ============================================// 使用示例// ============================================
int main() { // 创建灯光控制器 LightController* controller = new LightController();
// 模拟一个典型的使用流程
// 1. 启动系统 controller->evEnable(); // OFF -> ON (进入StartingUp + OK状态)
// 2. 系统运行中 controller->evRun(); // StartingUp -> Operational
// 3. 出现警告 controller->evWarning(); // OK -> Warning (黄灯)
// 4. 警告升级为错误 controller->evError(); // Warning -> Error (红灯)
// 5. 问题解决 controller->evOk(); // Error -> OK (绿灯)
// 6. 准备关闭 controller->evShutDown(); // Operational -> ShuttingDown
// 7. 关闭系统 controller->evDisable(); // ON -> OFF
// 8. 紧急情况演示 controller->evEnable(); // 重新启动 controller->evAbort(); // 紧急中止 -> EMERGENCY_STATE controller->reset(); // 重置回OFF状态
delete controller; return 0;}来源:CSDN 原文,首次发布于 2025-08-31。