FSM——squirrel状态机使用

news2025/7/21 21:34:37

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.coloradmin.cn/o/368555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++031-C++日期模拟

文章目录C031-C日期模拟日期模拟题目描述 给出天数求月份日期题目描述 给出天数求月份日期-倒计时题目描述 求任意日期插值在线练习&#xff1a;总结C031-C日期模拟 在线练习&#xff1a; http://noi.openjudge.cn/ https://www.luogu.com.cn/ 日期模拟 题目描述 给出天数求月…

CSS 网页动画【快速掌握知识点】

目录 前言 一、使用CSS3动画 二、使用CSS过渡 三、使用CSS变换&#xff1a; 前言 CSS是一种用于网页设计和排版的语言&#xff0c;也可以用它来制作网页动画。 一、使用CSS3动画 CSS3引入了动画属性&#xff0c;允许您为元素设置动画效果。您可以使用关键帧来定义动画的开始…

MVP简单模型搭建【架构】

MVP简介 MVP是一种项目架构设计模式&#xff08;说白了就是我们产品的一种设计方案&#xff09; 其实MVP本质 就是将View和Model完全隔离&#xff0c;通过Presenter统一调度管理&#xff08;Presenter扮演着中介的角色&#xff09;传统的设计思路是我们直接跟房东谈&#xff0…

聊聊动态线程池的9个场景(改进版)

线程池是一种基于 池化思想管理线程 的工具&#xff0c;使用线程池可以减少 创建销毁线程的开销&#xff0c;避免线程过多导致 系统资源耗尽。在 高并发以及大批量 的任务处理场景&#xff0c;线程池的使用是必不可少的。 如果有在项目中实际使用线程池&#xff0c;相信你可能…

数仓模型之维度建模

目录 1、数仓架构原则 2、如何搭建一个好的数仓 2.1 建模方法 2.2 建模解决的痛点 2.3 数仓系统满足的特性 2.4 数仓架构设计 3、维度建模 4、案例 5、问题讨论 今天我们来聊聊在数仓模型中举足轻重的维度建模。 简单而言&#xff0c;数据仓库的核心目标是为展现层提…

Hive学习——开窗函数精讲

目录 一、基于行的窗口函数——行的起点~行的终点 二、基于值的窗口函数——值的起点~值的终点 三、基于分区的窗口函数 四、基于缺省的窗口函数 五、lead与lag 六、first_value和last_value 七、排名函数——rank(113)、dense_rank(112)、row_number(123) 八、NTILE分…

nvm (node版本管理工具)安装的详细步骤,并解决安装过程中遇到的问题

1、下载NVM&#xff0c;跳转下载链接后&#xff0c;如下图&#xff0c;下载红框后解压文件 2、安装 注意&#xff1a;双击安装之后&#xff0c;会有两个地址选择&#xff0c; 1、地址中不能存在空格 2、不要放在C盘中&#xff0c;后面需要改个设置文件&#xff0c;安装到C盘的…

银行家算法

银行家算法 银行家算法是一种用来避免操作系统死锁出现的有效算法&#xff0c;所以在引入银行家算法的解释之前&#xff0c;有必要简单介绍一下死锁的概念。 一、死锁 死锁&#xff1a;是指两个或两个以上的进程在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成…

Gitlab Linux 环境安装

环境检查是否已经安装了gitlab&#xff0c;安装了需要卸载# 检查当前环境是否已经安装了gitlab&#xff0c;并且查看版本 gitlab-rails console # 删除命令 yum remove git# 查找命令 rpm -qa | grep gitlab # 删除命令 rpm -e gitlab-ce-12.10.1-ce.0.el8.x86_64 # 查找命令f…

DS期末复习卷(八)

一、选择题(30分) 1.字符串的长度是指&#xff08; C &#xff09;。 (A) 串中不同字符的个数 (B) 串中不同字母的个数 (C ) 串中所含字符的个数 (D) 串中不同数字的个数 2.建立一个长度为n的有序单链表的时间复杂度为&#xff08; C &#xff09; (A) O(n) (B) O(1) © …

小米/红米手机数据恢复:从小米手机恢复已删除的数据

如果您不小心删除了小米手机上的数据&#xff0c;后来发现您需要它&#xff0c;那么本文适合您。我将向您介绍一些最可靠的小米恢复方法&#xff0c;以将您的数据恢复到您的设备上。无论您是否有备份&#xff0c;都可以处理。让我们开始吧&#xff01; 小米数据恢复 - 如何做&a…

一篇学习JVM

基础入门 1.JDK、JRE、JVM三者间的联系与区别 JDK JDK(Java SE Development Kit)&#xff0c;Java标准开发包&#xff0c;它提供了编译、运行Java程序所需的各种工具和资源&#xff0c;包括Java编译器、Java运行时环境&#xff0c;以及常用的Java类库等。 下图是JDK的安装目…

博客管理系统--项目说明

项目体验地址&#xff08;账号&#xff1a;123&#xff0c;密码&#xff1a;123&#xff09;http://120.53.20.213:8080/blog_system/login.html项目码云Gitee地址&#xff1a;https://gitee.com/GoodManSS/project/tree/master/blog_system&#xff08;一&#xff09;准备工作…

【ArcGIS Pro二次开发】(7):地图(Map)的基本操作

地图是ArcGIS Pro中的基础起点&#xff0c;也是大多数工程的基础。主要用于显示表示空间数据的图层。 一、地图(Map)的基本操作示例 1、获取当前地图 var map MapView.Active.Map; 2、获取一级图层 var lys map.Layers; 用于获取地图中的单一图层&#xff0c;以及图层组…

【正点原子FPGA连载】第十六章DP彩条显示实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十六章DP彩条显…

什么是路由?

什么是路由&#xff1f; 介绍 **路由是指路由器从一个接口上收到数据包&#xff0c;根据数据包的目的地址进行定向并转发到另一个接口的过程。**路由发生在OSI网络参考模型中的第三层即网络层。 路由引导分组转送&#xff0c;经过一些中间的节点后&#xff0c;到它们最后的目…

六【 SpringMVC框架】

一 SpringMVC框架 目录一 SpringMVC框架1.什么是MVC2.SpringMVC概述3.SpringMVC常见开发方式4.SpringMVC执行流程5.SpringMVC核心组件介绍6.快速构建Spring MVC程序✅作者简介&#xff1a;Java-小白后端开发者 &#x1f96d;公认外号&#xff1a;球场上的黑曼巴 &#x1f34e;个…

工业三防平板可应用于各种复杂苛刻的工作环境

伴随着工业互联网技术的快速发展&#xff0c;生产制造自然环境繁杂&#xff0c;机器设备规定比较严苛。普通平板在工业场景户外场景等都比较容易出现磕碰或者出现其它因素如进水、进灰尘而引发设备故障。三防平板之所以在建筑工程的应用较为广泛&#xff0c;这与其独特的性能是…

线性数据结构:数组 Array

一、前言数组是数据结构还是数据类型&#xff1f;数组只是个名称&#xff0c;它可以描述一组操作&#xff0c;也可以命名这组操作。数组的数据操作&#xff0c;是通过 idx->val 的方式来处理。它不是具体要求内存上要存储着连续的数据才叫数组&#xff0c;而是说&#xff0c…

scratch和平使者 电子学会图形化编程scratch等级考试一级真题和答案解析2022年12月

目录 scratch和平使者 一、题目要求 1、准备工作 2、功能实现 二、案例分析