很多人一听状态机就觉得很复杂。好像要画图。要写框架。要搞一堆设计模式。其实在不少上位机项目里先不用想那么重。最重要的是把一件事想清楚当前状态下收到某个事件下一步应该变成什么状态。如果这个关系没想清楚代码里就会到处都是 if else。if else 一开始很好写项目刚开始状态少判断也少。比如voidController::start(){if(m_stateState::Idle){m_stateState::Running;m_device-start();}}这很正常。但后面要加暂停、继续、报警、复位。代码就会变成这样if(m_stateState::Idle){...}elseif(m_stateState::Running){...}elseif(m_stateState::Paused){...}elseif(m_stateState::Alarm){...}每个按钮里来一份。每个设备回调里再来一份。时间久了谁都不敢动。因为你不知道这个判断到底服务哪个流程。先把状态和事件写出来状态机不一定一开始就写得很正式。可以先把状态和事件列出来。比如一个很简单的流程enumclassState{Idle,Running,Paused,Alarm};enumclassEvent{Start,Pause,Resume,Stop,AlarmRaised,Reset};这样写的好处是项目里的人能先对齐语言。什么叫运行中。什么叫暂停。什么情况下能复位。这些话先说清楚代码才不会越写越随意。关键是限制不该发生的事状态机最有用的地方不是让代码看起来高级。而是限制一些不该发生的操作。比如空闲时可以启动。运行中可以暂停或停止。报警后只能复位。暂停时可以继续也可以停止。这些规则可以先写得直白一点boolController::canStart()const{returnm_stateState::Idle;}boolController::canReset()const{returnm_stateState::Alarm;}按钮是否可点也从这些函数来。不要界面上自己判断一套控制层又判断一套。判断多了迟早不一致。状态变化要集中上位机项目里最怕状态到处改。按钮里改一下。设备回调里改一下。定时器里改一下。异常处理里再改一下。后面出问题时很难知道状态到底是谁改的。可以先加一个统一入口voidController::setState(State state){if(m_statestate)return;appendLog(QString(状态变化%1 - %2).arg(stateText(m_state),stateText(state)));m_statestate;emitstateChanged(m_state);}这样至少能知道状态什么时候变了。界面也可以只监听stateChanged来刷新。状态不再靠各个按钮自己改。不用一上来追求完美很多项目不是缺一个复杂状态机框架。而是连最基本的状态边界都没想清楚。先做到这几件事就已经比一堆 if else 稳很多状态用枚举写清楚事件用名字说清楚哪些状态允许哪些操作状态变化统一入口状态变化写日志这些东西不花哨。但现场排查问题时很有用。状态能说清楚流程才不容易乱。
上位机状态机怎么写才不会变成一堆ifelse
发布时间:2026/6/30 16:37:13
很多人一听状态机就觉得很复杂。好像要画图。要写框架。要搞一堆设计模式。其实在不少上位机项目里先不用想那么重。最重要的是把一件事想清楚当前状态下收到某个事件下一步应该变成什么状态。如果这个关系没想清楚代码里就会到处都是 if else。if else 一开始很好写项目刚开始状态少判断也少。比如voidController::start(){if(m_stateState::Idle){m_stateState::Running;m_device-start();}}这很正常。但后面要加暂停、继续、报警、复位。代码就会变成这样if(m_stateState::Idle){...}elseif(m_stateState::Running){...}elseif(m_stateState::Paused){...}elseif(m_stateState::Alarm){...}每个按钮里来一份。每个设备回调里再来一份。时间久了谁都不敢动。因为你不知道这个判断到底服务哪个流程。先把状态和事件写出来状态机不一定一开始就写得很正式。可以先把状态和事件列出来。比如一个很简单的流程enumclassState{Idle,Running,Paused,Alarm};enumclassEvent{Start,Pause,Resume,Stop,AlarmRaised,Reset};这样写的好处是项目里的人能先对齐语言。什么叫运行中。什么叫暂停。什么情况下能复位。这些话先说清楚代码才不会越写越随意。关键是限制不该发生的事状态机最有用的地方不是让代码看起来高级。而是限制一些不该发生的操作。比如空闲时可以启动。运行中可以暂停或停止。报警后只能复位。暂停时可以继续也可以停止。这些规则可以先写得直白一点boolController::canStart()const{returnm_stateState::Idle;}boolController::canReset()const{returnm_stateState::Alarm;}按钮是否可点也从这些函数来。不要界面上自己判断一套控制层又判断一套。判断多了迟早不一致。状态变化要集中上位机项目里最怕状态到处改。按钮里改一下。设备回调里改一下。定时器里改一下。异常处理里再改一下。后面出问题时很难知道状态到底是谁改的。可以先加一个统一入口voidController::setState(State state){if(m_statestate)return;appendLog(QString(状态变化%1 - %2).arg(stateText(m_state),stateText(state)));m_statestate;emitstateChanged(m_state);}这样至少能知道状态什么时候变了。界面也可以只监听stateChanged来刷新。状态不再靠各个按钮自己改。不用一上来追求完美很多项目不是缺一个复杂状态机框架。而是连最基本的状态边界都没想清楚。先做到这几件事就已经比一堆 if else 稳很多状态用枚举写清楚事件用名字说清楚哪些状态允许哪些操作状态变化统一入口状态变化写日志这些东西不花哨。但现场排查问题时很有用。状态能说清楚流程才不容易乱。