FSM——squirrel状态机使用

news/2024/4/19 12:38:19/文章来源:https://blog.csdn.net/weixin_45565886/article/details/129197762

FSM——squirrel状态机使用

1 FSM介绍

1.1 概念

FSM(finite state machine):有限状态机

  • 是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
  • 核心内容:有限个状态、通过外部操作引起状态的转移。
  • 用来对状态的流转进行解耦,使代码逻辑更加清楚和更加容易维护

1.2 组成和分类

  • 组成
  1. 现态:当前所处状态
  2. 条件(事件):当一个条件被满足,可能会触发一个动作,或执行一次状态的迁移。
  3. 动作:条件满足后执行的动作行为。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原有状态。动作不是必须的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
  4. 次态:条件满足后要迁往的新状态。"次态"是相对于"现态"而言的,"次态"一旦被激活,就转变为新的"现态"了。

总结:

所有的状态转换都可以概括为:
F(S, E) -> (A,S'):即如果当前状态为S,接收到一个事件E,则执行动作A,同时状态转换为下个状态S’

  • 分类
  • F(S) -> (A, S’) 型状态机:下一状态只由当前状态决定
  • F(S, E) -> (A, S’) 型状态机:下一状态不但与当前状态有关,还与当前输入值有关

2 使用

2.1 squirrel状态机框架

就像松鼠一样,小巧,灵活,智能,警觉和可爱的动物,squirrel基础旨在为企业使用提供轻量级,高度灵活和可扩展,可诊断,易于使用和类型安全的Java状态机实现。
squirrel文档:https://www.yangguo.info/2015/02/01/squirrel/

代码中使用:

<!--FSM 状态机-->
<dependency><groupId>org.squirrelframework</groupId><artifactId>squirrel-foundation</artifactId><version>0.3.8</version>
</dependency>

2.1.1 普通实现

①事件枚举类
public enum Event {/*** 审批通过*/APPROVE_PASS,/*** 审批拒绝*/APPROVE_REFUSED,/*** 复核通过*/RECHECK_PASS,/*** 复核不通过*/RECHECK_REFUSED;
}
②状态枚举类
public enum State {/*** 待审核*/APPROVE,/*** 拒绝*/REFUSED,/*** 同意*/PASS;
}
③上下文参数
@Getter
@Setter
@AllArgsConstructor
public class Context {private String param;
}
④自定义状态机(继承抽象类)
public class StateMachine extends AbstractStateMachine<StateMachine, State, Event, Context> {private void approvePassAction(State from, State to, Event event, Context context) {System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为通过", context.getParam()));//TODO 将审批状态更新为已审核通过}private void approveRefusedAction(State from, State to, Event event, Context context) {System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为拒绝", context.getParam()));//TODO 将审批状态更新为审核拒绝}private void recheckPassAction(State from, State to, Event event, Context context) {System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为通过", context.getParam()));//TODO 将审批状态更新为审核通过}private void recheckRefusedAction(State from, State to, Event event, Context context) {System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为不通过", context.getParam()));//TODO 将审批状态更新为审核不通过}
}

⑤测试状态机

一般是通过controller请求发起状态机调用,此处为了简单就直接在main方法中调用发起

public class Test {public static void main(String[] args) {StateMachineBuilder<StateMachine, State, Event, Context> builder =StateMachineBuilderFactory.create(StateMachine.class, State.class, Event.class, Context.class);/*** 状态转移表*///F(APPROVE,APPROVE_PASS)->(PASS,approvePassAction)builder.externalTransition().from(APPROVE).to(PASS).on(APPROVE_PASS).callMethod("approvePassAction");//F(APPROVE,APPROVE_REFUSED)->(REFUSED,ApproveRefusedAction)builder.externalTransition().from(APPROVE).to(REFUSED).on(APPROVE_REFUSED).callMethod("approveRefusedAction");//F(REFUSED,RECHECK_PASS)->(PASS,RecheckPassAction)复核 - 通过builder.externalTransition().from(REFUSED).to(PASS).on(RECHECK_PASS).callMethod("recheckPassAction");//F(REFUSED,RECHECK_REFUSED)->(REFUSED,RecheckRefusedAction)builder.externalTransition().from(REFUSED).to(REFUSED).on(RECHECK_REFUSED).callMethod("recheckRefusedAction");StateMachine machine = builder.newStateMachine(APPROVE);Context ziyi = new Context("ziyi");Context ka = new Context("ka");machine.start();//ziyi审批拒绝machine.fire(APPROVE_REFUSED,ziyi);ka复核成功//machine.fire(RECHECK_PASS,ka);}}

手动builder添加状态转移:
待审核 - 审核同意 - 复核通过

运行结果:
在这里插入图片描述

2.1.2 注解实现

可以直接通过@Transitions注解定义多个状态转变,指定从from状态到那to状态,然后on在哪个事件,最后callMethod(调用)哪个方法

@Transitions({@Transit(from = "APPROVE", to = "REFUSED", on = "APPROVE_REFUSED", callMethod = "approveRefusedAction"),
})
public class StateMachine extends AbstractStateMachine<StateMachine, State, Event, Context> {...
}

其他示例:

/*** 定义 触发事件、状态变化时,调用的方法* @States 定义状态列表,里面可以包含多个状态* @State定义每个状态,name状态名称,entryStateInit进入状态时调用的方法,exitCallMethod 离开状态是调用的方法,initialState 为true时,为默认状态。* */
@States({@State(name = "INIT", entryCallMethod = "entryStateInit", exitCallMethod = "exitStateInit", initialState = true),@State(name = "WAIT_PAY", entryCallMethod = "entryStateWaitPay", exitCallMethod = "exitStateWaitPay"),@State(name = "WAIT_SEND", entryCallMethod = "entryStateWaitSend", exitCallMethod = "exitStateWaitSend"),@State(name = "PART_SEND", entryCallMethod = "entryStatePartSend", exitCallMethod = "exitStatePartSend"),@State(name = "WAIT_RECEIVE", entryCallMethod = "entryStateWaitReceive", exitCallMethod = "exitStateWaitReceive"),@State(name = "COMPLETE", entryCallMethod = "entryStateComplete", exitCallMethod = "exitStateComplete")
})
@Transitions({@Transit(from = "INIT", to = "WAIT_PAY", on = "SUBMIT_ORDER", callMethod = "submitOrder"),@Transit(from = "WAIT_PAY", to = "WAIT_SEND", on = "PAY", callMethod = "pay"),@Transit(from = "WAIT_SEND", to = "PART_SEND", on = "PART_SEND", callMethod = "partSend"),@Transit(from = "PART_SEND", to = "WAIT_RECEIVE", on = "SEND", callMethod = "send"),@Transit(from = "WAIT_RECEIVE", to = "COMPLETE", on = "COMPLETE", callMethod = "complete")
})
// @StateMachineParameters用来声明状态机泛型参数类型,向AbstractStateMachine传递参数
@StateMachineParameters(stateType = OrderState.class, eventType = OrderEvent.class, contextType = OrderContext.class)
@Slf4j
public class SubmitOrderStateMachine extends AbstractStateMachine<UntypedStateMachine, Object, Object, Object> implements UntypedStateMachine {.......
}

参考:
https://blog.csdn.net/footless_bird/article/details/115797710

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_73869.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高等工程数学张韵华版第二章课后题

答案仅供参考 本章内容 第 2 章 线性空间 2.1 向量的相关性 2.1.1 线性组合和线性表示 2.1.2 线性相关与线性无关 2.2 秩 2.2.1 向量组的秩 2.2.2 矩阵的秩 2.2.3 相抵标准形 2.3 线性空间 2.3.1 线性空间的定义 2.3.2 线性子空间 2.4 维、基、坐标 2.4.1 维、基、坐标的定义…

复杂场景的接口测试

测试场景一&#xff1a;被测业务操作是由多个API调用协作完成 背景&#xff1a;一个单一的前端操作可能会触发后端一系列的API调用&#xff0c;此时API的测试用例就不再是简单的单个API调用&#xff0c;而是一系列API的调用 存在的情况&#xff1a;存在后一个API需要使用前一个…

springboot+vue软件bug项目测试过程管理系统

config&#xff1a;主要用来存储配置文件&#xff0c;以及其他不怎么动用的信息 controller&#xff1a;项目的主要控制文件 dao: 主要用来操作数据库 entity: 实体&#xff0c;用来放与数据库表里对应的实体类&#xff0c;表中的字段对应类中的属性值&#xff0c;并…

视觉SLAM数据集(一):TUM DataSet

首先给出数据集下载地址&#xff1a;TUM Dataset Download。 如果你是第一次做实验&#xff0c;建议下载xyz的数据集&#xff0c;因为它的动作相对很小&#xff0c;只包含桌面上的一小部分。一旦成功测试&#xff0c;就可以试试desk数据集&#xff0c;它包含四张桌子和几个闭环…

C语言的学习小结——数组

一、一维数组的创建与初始化 1、格式&#xff1a; type_t arr_name[const_n];//type_t 是指数组的元素类型 //const_n 是一个常量表达式&#xff0c;用来指定数组的大小 注&#xff1a; 数组是使用下标来访问的&#xff0c;下标从0开始。 数组的大小可以通过计算得到&…

电商平台商品详情接口的应用场景

API接口的定义价格、库存量、发货地点等。此外&#xff0c;它还可以提供商品的详细信息&#xff0c;包括商品的图片、详细描述、规格参数、售后服务等。这些信息可以帮助用户更好地了解商品&#xff0c;从而更好地选择商品。其次&#xff0c;电商平台商品详情接口的实现原理是基…

使用Chemistry Development Kit (CDK) 来进行化学SMILES子结构匹配

摘要 SMILES是一种用于描述化合物结构的字符串表示法&#xff0c;其中子结构搜索是在大规模化合物数据库中查找特定的结构。然而&#xff0c;这种搜索方法存在一个误解&#xff0c;即将化合物的子结构视为一个独立的实体进行搜索&#xff0c;而忽略了它们在更大的化合物中的上…

极光笔记 | 埋点体系建设与实施方法论

PART 01 前 言随着网络技术的发展&#xff0c;从粗犷型到精细化运营型&#xff0c;再到现在的数字化运营&#xff0c;数据变得越来越细分和重要&#xff0c;不仅可以进行策略调整&#xff0c;还可以实现自动化的精细化运营。而数据价值的起点就是埋点&#xff0c;只有合理地埋点…

lammps教程:Ovito选择特定晶粒的方法

大家好&#xff0c;我是小马老师。 本文介绍如何使用ovito提取特定的晶粒。 在多晶的lammps模拟中&#xff0c;可能会对某一个特定晶粒的变形情况进行分析&#xff0c;此时&#xff0c;需要找到这个晶粒&#xff0c;并进行单独分析。 ovito有专用的晶粒识别命令&#xff0c;…

【系统分析师之路】2022上案例分析历年真题

【系统分析师之路】2022上案例分析历年真题 【系统分析师之路】2022上案例分析历年真题【系统分析师之路】2022上案例分析历年真题2022上案例分析历年真题第一题&#xff08;25分&#xff09;2022上案例分析历年真题第二题&#xff08;25分&#xff09;2022上案例分析历年真题第…

RocketMQ 5.x新版本部署优化一览

​ RocketMQ从2022年9月份开始推出了新的5.x大版本。相比于之前的4.x版本&#xff0c;5.x版本向云原生前进了一大步。在增强原因功能的基础上&#xff0c;更是支持多语言客户端&#xff0c;周边生态也进行了补强和完善&#xff0c;明显可以看到离Kafka老大哥又近了很大一步。 …

由Geoscene Enterprise 2.1 升级至Geoscene Enterprise 3.1

文章目录一、升级前工作二、升级Geoscene portal三、升级Web Adaptor&#xff08;针对portal门户&#xff09;四、升级Server 站点&#xff08;作为门户托管服务器&#xff09;五、升级Web Adaptor&#xff08;针对server&#xff09;六、升级Data Store需求&#xff1a;由GeoS…

springboot自定义starter时使用@AutoConfigureBefore、@AutoConfigureAfter的细节问题

正常利用springboot的自动装配 ConfB Configuration(proxyBeanMethodsfalse) public class ConfB {public ConfB(){System.out.println("ConfB构造方式执行...");} }不加spring.factories 项目包结构 此时resources中没有spring.factories 执行结果 2023-02-24…

教你用反射机制如何几分钟搭建完后端

如果想快速搭建后台跨域使用这些技术 反射mybatis-plusjson 反射可以实现动态数据的传输 一般对数据库进行操作肯定离不开这些代码 如果我们用反射机制只需要这一个就行 而说到反射的好处&#xff0c;一般情况下我们做增删改查需要大量的接口才能完成&#xff0c;而用反射我…

通过操作Cortex-A7核,串口输入相应的命令,控制LED灯进行工作

1.通过操作Cortex-A7核&#xff0c;串口输入相应的命令&#xff0c;控制LED灯进行工作 例如在串口输入led1on,开饭led1灯点亮 2.例如在串口输入led1off,开饭led1灯熄灭 3.例如在串口输入led2on,开饭led2灯点亮 4.例如在串口输入led2off,开饭led2灯熄灭 5.例如在串口输入led…

LabVIEW主VI前面板中显示或使用多个子VI

LabVIEW主VI前面板中显示或使用多个子VI想在程序中连接一个或多个子VI的前面板&#xff0c;但是当调用它们时&#xff0c;每个子VI在计算机屏幕上显示为一个新窗口。那么怎么能让每个子VI作为主VI前面板的一部分进行显示&#xff0c;而不是在屏幕上显示多个窗口&#xff1f;正在…

Malware Dev 00 - Rust vs C++ 初探

写在最前 如果你是信息安全爱好者&#xff0c;如果你想考一些证书来提升自己的能力&#xff0c;那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里&#xff1a; https://discord.gg/9XvvuFq9Wb我会提供备考过程中尽可能多的帮助&#xff0c;并分享学习和实践过程…

mysql 内存架构

1. 背景 从 innodb 的整体架构中可以知道 innodb 的内存架构中分为 buffer pool 缓存区, change pool 修改缓冲区, adaptive hash index 自适应哈希索引, 和 log buffer 日志缓冲区. 2. buffer pool buffer pool 是用于缓冲磁盘页的数据&#xff0c;mysql 的80%的内存会分配给…

GroupDocs.Merger for Java

GroupDocs.Merger for Java GroupDocs.Merger for Java是一个文档操作API&#xff0c;可帮助您合并、拆分、交换或删除文档页面。API通过启用或禁用密码提供保护&#xff0c;并允许开发人员加入PDF、Microsoft Word、Excel和Powerpoint文档。 支持的文件格式 Microsoft Office格…

内存管理框架---Slab(二)

站在Arnold Lu南京大佬的肩膀&#xff0c;俯瞰内存管理之slab 文章目录slab层的由来slab/slub/slobslab层的设计思想slab相关数据结构创建slab描述符分配slab对象释放slab对象销毁缓存在内核栈上的静态分配高端内存的映射永久映射临时映射每个CPU的分配新的每个CPU接口编译时的…