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

状态机——事件流中的事件合成

事件流中的事件合成

    • 1、问题描述
    • 2、核心设计思路
    • 3、代码实现
    • 5、表达式解析器

1、问题描述

有一组连续的子事件流,类似1, 2, 3, 4, 5,6…,子事件会合成事件,逻辑类似与(1 & 2 & (3 | 4)) & 5,如何用状态机实现

对于这种包含复杂逻辑嵌套(与、或、顺序流转)的连续子事件流,如果单纯用前面提到的基础状态机(比如一个状态变量或简单的集合),代码会变得极难扩展且容易写出“屎山”。

最优雅的工业级解法是:状态机(State Machine) + 抽象语法树 / 组合模式(Composite Pattern)。

我们可以把(1 & 2 & (3 | 4)) & 5这种逻辑表达式看作是一个动态的生命周期树(或者叫条件流转节点)。状态机负责推进全局主状态,而这个“树形节点”负责判断何时满足流转条件。

2、核心设计思路

  1. 基础事件/子事件(Event):代表流转中的 1, 2, 3, 4, 5…
  2. 逻辑节点(Node):
    • 叶子节点(LeafNode):对应具体的单事件(如 1)。当该事件发生时,它被标记为“已触发”。
    • 与节点(AndNode):只有当所有子节点都为 true 时,它才为 true。
    • 或节点(OrNode):只要有一个子节点为 true,它就为 true。

3、代码实现

第一步:构建逻辑节点框架(组合模式)
这是整个逻辑判断的核心。它能够完美嵌套任意复杂的类似 ((1 & 2) | (3 & 4)) & 5 的逻辑

publicinterfaceLogicNode{booleanisSatisfied();// 当前节点是否已满足voidtrigger(inteventId);// 触发子事件voidreset();// 重置状态}// 1. 叶子节点:代表具体某个子事件(如 1,2,3)classEventLeafNodeimplementsLogicNode{privatefinalinteventId;privatebooleantriggered=false;publicEventLeafNode(inteventId){this.eventId=eventId;}@OverridepublicbooleanisSatisfied(){returntriggered;}@Overridepublicvoidtrigger(intid){if(this.eventId==id){this.triggered=true;}}@Overridepublicvoidreset(){this.triggered=false;}}// 2. 与节点(And):所有子节点必须全部满足classAndNodeimplementsLogicNode{privatefinalList<LogicNode>children=newArrayList<>();publicAndNode(LogicNode...nodes){children.addAll(Arrays.asList(nodes));}@OverridepublicbooleanisSatisfied(){returnchildren.stream().allMatch(LogicNode::isSatisfied);}@Overridepublicvoidtrigger(inteventId){children.forEach(child->child.trigger(eventId));}@Overridepublicvoidreset(){children.forEach(LogicNode::reset);}}// 3. 或节点(Or):子节点满足其一即可classOrNodeimplementsLogicNode{privatefinalList<LogicNode>children=newArrayList<>();publicOrNode(LogicNode...nodes){children.addAll(Arrays.asList(nodes));}@OverridepublicbooleanisSatisfied(){returnchildren.stream().anyMatch(LogicNode::isSatisfied);}@Overridepublicvoidtrigger(inteventId){children.forEach(child->child.trigger(eventId));}@Overridepublicvoidreset(){children.forEach(LogicNode::reset);}}

第二步:结合全局状态机(StateMachine)
现在我们定义全局的业务主状态,并让它持有上面构造出来的逻辑树。

//全局主状态publicenumMainState{INIT,// 初始PROCESSING,// 处理中(子事件收集阶段)COMPLETED// 目标事件合成成功}// 状态机上下文classEventStateMachine{privateMainStatecurrentState=MainState.INIT;privatefinalLogicNoderootCondition;// 复合条件树publicEventStateMachine(LogicNoderootCondition){this.rootCondition=rootCondition;}// 接收连续传入的子事件publicsynchronizedvoidfeedEvent(inteventId){if(currentState==MainState.COMPLETED){System.out.println("状态已是 COMPLETED,忽略事件: "+eventId);return;}if(currentState==MainState.INIT){currentState=MainState.PROCESSING;}// 1. 将事件送入逻辑树中消费rootCondition.trigger(eventId);System.out.println("收到子事件 ["+eventId+"]");// 2. 状态机检查逻辑树是否整体达到了“满足”条件if(rootCondition.isSatisfied()){this.currentState=MainState.COMPLETED;System.out.println("🎉 满足公式组合条件!成功合成为目标事件。当前全局状态 -> "+currentState);}}publicMainStategetCurrentState(){returncurrentState;}}

** 测试运行:验证 (1 & 2 & (3 | 4)) & 5**

publicclassMain{publicstaticvoidmain(String[]args){// 1. 根据公式构建逻辑树: (1 & 2 & (3 | 4)) & 5LogicNodeleaf1=newEventLeafNode(1);LogicNodeleaf2=newEventLeafNode(2);LogicNodeleaf3=newEventLeafNode(3);LogicNodeleaf4=newEventLeafNode(4);LogicNodeleaf5=newEventLeafNode(5);// (3 | 4)LogicNodeor34=newOrNode(leaf3,leaf4);// (1 & 2 & (3 | 4)) & 5LogicNodeformulaRoot=newAndNode(leaf1,leaf2,or34,leaf5);// 2. 传入状态机EventStateMachinestateMachine=newEventStateMachine(formulaRoot);// 3. 模拟事件流乱序流入stateMachine.feedEvent(1);// 满足 1stateMachine.feedEvent(99);stateMachine.feedEvent(5);// 满足 5stateMachine.feedEvent(4);// 满足 (3 | 4) 中的 4System.out.println("-> 当前全局状态: "+stateMachine.getCurrentState());// 应该仍是 PROCESSING,因为缺 2System.out.println("----------------------------------------");stateMachine.feedEvent(2);// 满足 2,此时公式全部闭环!System.out.println("-> 最终全局状态: "+stateMachine.getCurrentState());// 成功变为 COMPLETED}}
收到子事件 [1] 收到子事件 [99] 收到子事件 [5] 收到子事件 [4] -> 当前全局状态: PROCESSING ---------------------------------------- 收到子事件 [2] 🎉 满足公式组合条件!成功合成为目标事件。当前全局状态 -> COMPLETED -> 最终全局状态: COMPLETED

方案优势:

  1. 支持无限嵌套:后续如果业务调整,逻辑变成 ((1 & 2) | (3 & 4)) & (5 | 6),你不需要修改核心逻辑和状态机代码,只需要改动几行组装逻辑树的代码(甚至可以写一个简单的解析器,把规则字符串直接变成这棵树)。
  2. 职责分离:全局状态机只管大方向的生命周期(开始 -> 处理 -> 完成),复杂的子事件联动逻辑全封闭在 LogicNode 内,符合面向对象的开闭原则(OCP)。

5、表达式解析器

要实现将规则字符串(如(1 & 2 & (3 | 4)) & 5)直接转换成前面定义的 LogicNode 树,我们需要编写一个简易的表达式解析器(Parser)。

最经典的实现方式是双栈法(Dijkstra’s Shunting-yard 算法的变体),一个栈用来存操作数(Node),另一个栈用来存操作符(&,|,()。由于我们的事件都是数字,这种方法实现起来最快、最直观。

publicclassRuleParser{publicstaticLogicNodeparse(Stringexpression){// 1. 去除所有空格expression=expression.replaceAll("\\s+","");//操作数栈Stack<LogicNode>nodes=newStack<>();//操作符栈Stack<Character>operators=newStack<>();inti=0;while(i<expression.length()){//遍历获取第一个字符charc=expression.charAt(i);// 情况 1: 如果是数字,解析出完整的事件 ID 并生成叶子节点if(Character.isDigit(c)){StringBuildersb=newStringBuilder();//处理事件ID为多位数字的情况while(i<expression.length()&&Character.isDigit(expression.charAt(i))){sb.append(expression.charAt(i));i++;}//创建叶子节点并入操作数栈nodes.push(newEventLeafNode(Integer.parseInt(sb.toString())));continue;// 跳过后面的 i++,因为上面已经递增过了}// 情况 2: 左括号直接入栈elseif(c=='('){//入操作符栈operators.push(c);}// 情况 3: 右括号,触发计算直到遇到左括号elseif(c==')'){while(!operators.isEmpty()&&operators.peek()!='('){executeOperator(nodes,operators.pop());}operators.pop();// 弹出 '('}// 情况 4: 操作符 & 或 |elseif(c=='&'||c=='|'){// 当栈顶操作符优先级更高或相等时,先计算while(!operators.isEmpty()&&precedence(operators.peek())>=precedence(c)){executeOperator(nodes,operators.pop());}operators.push(c);}i++;}// 2. 遍历完字符串后,清空操作符栈while(!operators.isEmpty()){executeOperator(nodes,operators.pop());}// 3. 栈顶就是最终构建好的根节点returnnodes.pop();}// 定义操作符优先级 (括号最低,& 最高,遵循常规逻辑运算)privatestaticintprecedence(charop){if(op=='&')return2;if(op=='|')return1;return0;// '('}// 弹出栈顶的节点,用指定的操作符把它们结合成复合节点,再压回栈privatestaticvoidexecuteOperator(Stack<LogicNode>nodes,charop){if(nodes.size()<2){thrownewIllegalArgumentException("非法规则表达式");}LogicNoderight=nodes.pop();LogicNodeleft=nodes.pop();if(op=='&'){// 如果左节点本身已经是 AndNode,可以直接追加,优化树的层级(可选)nodes.push(newAndNode(left,right));}elseif(op=='|'){nodes.push(newOrNode(left,right));}}}

配合状态机进行测试验证

publicclassMain2{publicstaticvoidmain(String[]args){// 1. 定义动态规则字符串StringruleStr="((1 | 2) & 8 & (3 | 4)) & 5";System.out.println("正在解析规则: "+ruleStr);// 2. 一键解析成一棵树LogicNodeformulaRoot=RuleParser.parse(ruleStr);// 3. 丢进状态机EventStateMachinestateMachine=newEventStateMachine(formulaRoot);// 4. 模拟输入事件流进行测试stateMachine.feedEvent(1);// 满足 1stateMachine.feedEvent(5);// 满足 5stateMachine.feedEvent(4);// 满足 (3 | 4)stateMachine.feedEvent(2);stateMachine.feedEvent(8);System.out.println("-> 当前状态: "+stateMachine.getCurrentState());System.out.println("----------------------------------------");stateMachine.feedEvent(2);// 满足 2 -> 整个公式成立!System.out.println("-> 最终状态: "+stateMachine.getCurrentState());}}
正在解析规则:((1|2)&8&(3|4))&5收到子事件[1]收到子事件[5]收到子事件[4]收到子事件[2]收到子事件[8]🎉 满足公式组合条件!成功合成为目标事件。当前全局状态->COMPLETED->当前状态:COMPLETED----------------------------------------状态已是COMPLETED,忽略事件:2->最终状态:COMPLETED
http://www.jsqmd.com/news/843570/

相关文章:

  • 3分钟掌握ncmdump:终极NCM音乐解密完全指南
  • 青岛治疗焦虑抑郁的医院哪家靠谱 - 品牌排行榜
  • 做出口品质的香菇装袋扎口一体机推荐与价格分析 - mypinpai
  • 2026年5月靠谱的东莞数码墨水厂家推荐:东莞市优墨数字喷墨技术、热转印墨水/UV墨水/弱溶剂墨水/烫画墨水选购指南 - 海棠依旧大
  • 3步开启你的智能狩猎助手:HunterPie全方位使用指南
  • 2026年4月移动房屋建设公司口碑推荐,轻钢别墅房屋/农村自建别墅/自建房农村别墅/钢结构别墅,移动房屋设计公司推荐 - 品牌推荐师
  • 2026年5月热门的北京镀锌槽钢批发厂家如何选厂家推荐榜,Q235B/Q355B/热镀锌槽钢厂家选择指南 - 海棠依旧大
  • 智慧司法调解庭建设品牌哪家好?太振科技怎么样? - mypinpai
  • 怎么辨别真自研降 AI 工具 vs 套壳 ChatGPT?5 条铁律帮你把 AI 率一次降到位
  • 博尚600/800型|中小型食用菌厂主力,出料均匀,省人工省成本 - 会飞的懒猪
  • 拯救者笔记本性能调优终极指南:Lenovo Legion Toolkit深度解析
  • 技术深潜:Play Integrity API如何重塑Android应用安全边界?
  • 从零搭建 Python 版 RAG 智能问答知识库|本地离线文档检索大模型实战
  • 2025-2026年全球重卡充电桩品牌推荐:五大排名厂家专业评测矿区应对恶劣环境 - 品牌推荐
  • vscode-R完全生存手册:从RStudio到现代开发环境的无缝迁移指南
  • 拉格朗日乘子法针对传统代入求解的优势
  • 2026年5月有实力的哈尔滨医学专升本机构哪家强厂家推荐榜:医学类专业专升本培训机构选择指南 - 海棠依旧大
  • 如何在5分钟内掌握Blender 3MF插件:3D打印工作流终极指南
  • 橡塑保温棉产品靠谱吗?廊坊德亿节能科技为你揭秘 - 工业品牌热点
  • ARM Linux电子墨水屏驱动开发:从FUSE接口到Python应用实践
  • 2025-2026年国内电动阀门厂家推荐:十大排行产品专业评测应对水处理高腐蚀介质痛点 - 品牌推荐
  • 对比直接使用厂商API在Taotoken平台管理密钥的便利性
  • 影刀RPA跨境店群运营架构实战:Python协同多实例隔离与高并发任务调度系统
  • AI摘要API接口调用接入实战指南,避坑攻略(附代码)
  • 靠谱的朋友圈广告公司,如何选择与收费标准 - 工业品牌热点
  • GHelper技术深度解析:华硕硬件控制的轻量化革命与架构创新
  • 即食海参的选购指南,百年晓芹值得选吗 - mypinpai
  • 情绪消费崛起,打通全链路的不是卖点,而是选择理由
  • 别让Stateflow代码生成翻车!MAB建模规范中那些容易被忽略的‘坑’与最佳实践
  • 【NotebookLM强化学习辅助实战指南】:20年AI架构师亲授5大落地场景与避坑清单