SpringBoot系列——状态机(附完整源码)
1. 简单介绍状态机
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。以上是百度百科对状态机的解释。
在百科的解释中,我们可以提炼出状态机的几个要素:存储状态,逻辑电路,预先设定的状态转移路径,外部来的信号,内置的特定操作等。由这些关键要素我们可以推断出以下几点:
状态数据有预先设定的多种值
逻辑电路是完成内置特定操作的基础“代码“(基础设施),由工程司开发
状态能在多种值之间转移
每次转移都由外部信号触发
状态转移触发后,会有相应的内置操作
由以上这些特性共同构成了一个独立的控制中心,而且这个控制中心与外部各种信号是低耦合的,所有外部信号都要接入一个共同的控制中心,最终也由控制中心完成信号的后续流程。
在java开发中,状态机FSM(有限状态机)是一种常见的设计模式,常常用于一些复杂的业务场景,解决繁琐杂乱的if...else...代码段。
“Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.“
-对象内部状态不同会有不同的行为。似乎好像是不同的类一样。
以电梯为例,电梯有4种状态:开门、关门、运行、停止。电梯的动作:开门、关门、运行(上升或下降)、停止(悬停不动)。
| Col1 | 开门行为 | 关门行为 | 运行行为 | 停止行为 |
|---|---|---|---|---|
| 开门 态 | ❌ | ✔ | ❌ | ❌ |
| 关门 态 | ✔ | ❌ | ✔ | ✔ |
| 运行 态 | ❌ | ❌ | ❌ | ✔ |
| 停止 态 | ✔ | ❌ | ✔ | ❌ |
开门状态下,电梯只有关门行为
关门状态下,除了关门行为其他行为都有
运行状态下,只有停止行为
停止状态下,有开门行为和运行行为
状态图如下:
状态机设计模式的好处:
降低程序的复杂度;
提高程序的可维护性;
状态机模式体现了开闭原则和单一职责原则。
每个状态都是一个子类,增加状态就要增加子类;修改状态只要修改一个类就行了。
这种设计模式将每个状态的变更后的处理逻辑都做了统一封装,跟业务代码耦合,只接收相互约定的信号(事件)。
2. 状态机的本质
由状态机的几个要素我们也可以知道,在一个复杂的业务流程过程中,有多种数据状态,多种处理动作,以及多种维度的角色。在这样复杂业务场景下,如果只是简单使用if...else...语句,首先可读性就非常差,而且维护起来非常困难,甚至是开发人员都没办法理清楚自己写的if..else语句。如果复杂的业务流程有了变更和新增,那这个维护起来就是个灾难,各种复杂问题不得而知。就像下图一样

用if..else..代码来开发复杂的业务流程,会面临下面几个问题:
复杂的业务流程,if.else代码几乎无法维护
随着业务的发展,业务过程也需要变更及扩展,但if.else代码段已经无法支持
没有可读性,变更风险特别大,可能会牵一发而动全身,给服务带来S级风险。
其他业务逻辑可能也会跟if.else代码块耦合在一起,带来更多的问题。
这时候,状态机就是个非常好的解决方案,能有效地解决这些问题。
一个状态机定义以后,在某个状态下就只接收固定的Event,也就是执行指定的操作,这样流程就能按照预期定义的那样流转,不会出现乱入的情况,执行了一些在某状态下不允许执行的操作,也就是说,状态的流转都是在控制范围,不会超出预设的状态空间。
状态机建立的控制中心是跟外界低耦合的,通过event通信。
控制中心所有的状态都是预设好的,不会超预料。
状态的跳转都是有设定控制条件的,会按照预设的转移路径运动。
状态机还非常容易的扩展和变更,支持因业务的发展而变更或扩展复杂业务流程
3. 状态机应用场景
状态机典型的应用有工作流引擎,游戏中人物状态变化引擎,订单交易等。前两种非常复杂,下面我就简单以订单交易这个场景来聊聊状态机的应用场景以及基于spring statemachine的项目。
配置pom依赖:
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
状态枚举和事件枚举:
/**
* @author Batman create on 2019-05-07 14:59
* 状态枚举类
*/
public enum States { /*
待支付
*/
UNPAID, /*
待收货
*/
WAITING_FOR_RECEIVE, /*
结束
*/
DONE, /*
退货中
*/
WAITING_FOR_GOODSBACK } /**
* @author Batman create on 2019-05-07 15:00
*/
public enum Events {
/*
支付
*/
PAY, /*
收货
*/
RECEIVE, /*
退货
*/
GOODS_REJECTED, /*
退款
*/
REFUND
}
欢迎加入技术群:获得更多java,springboot,redis,kafka圈的好友,共图技术未来
还要配置状态转移信息以及事件处理器逻辑的开发。完整的demo项目,请关注公众号"前沿科技bot"并发送"状态机"获取。

SpringBoot系列——状态机(附完整源码)的更多相关文章
- 在WebBrowser中执行javascript脚本的几种方法整理(execScript/InvokeScript/NavigateScript) 附完整源码
[实例简介] 涵盖了几种常用的 webBrowser执行javascript的方法,详见示例截图以及代码 [实例截图] [核心代码] execScript方式: 1 2 3 4 5 6 7 8 9 1 ...
- 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件)
单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 说实话很不想写这篇文章,因为这和我一贯推崇的最好全部编译并使用w ...
- 单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)
单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件) webrtc的音频处理模块分为降噪ns,回音消除aec,回声 ...
- 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件)
webrtc的音频处理模块分为降噪ns和nsx,回音消除aec,回声控制acem,音频增益agc,静音检测部分.另外webrtc已经封装好了一套音频处理模块APM,如果不是有特殊必要,使用者如果要用到 ...
- 基于spring-boot和docker-java实现对docker容器的动态管理和监控[附完整源码下载]
(我是个封面) docker简介 Docker 是一个开源的应用容器引擎,和传统的虚拟机技术相比,Docker 容器性能开销极低,因此也广受开发者喜爱.随着基于docker的开发者越来越多,doc ...
- Android自定义组合控件详细示例 (附完整源码)
在我们平时的Android开发中,有时候原生的控件无法满足我们的需求,或者经常用到几个控件组合在一起来使用.这个时候,我们就可以根据自己的需求创建自定义的控件了,一般通过继承View或其子类来实现. ...
- .NET Core中JWT+Auth2.0实现SSO,附完整源码(.NET6)
一.简介 单点登录(SingleSignOn,SSO) 指的是在多个应用系统中,只需登录一次,就可以访问其他相互信任的应用系统. JWT Json Web Token,这里不详细描述,简单说是一种认证 ...
- Java导出Excel(附完整源码)
导出excel是咱Java开发的必备技能啦,之前项目有这个功能,现在将其独立出来,分享一下.所用技术就是SpringBoot,然后是MVC架构模式.废话不多说,直接上代码了,源码点末尾链接就可以下载. ...
- Android静态图片人脸识别的完整demo(附完整源码)
Demo功能:利用android自带的人脸识别进行识别,标记出眼睛和人脸位置.点击按键后进行人脸识别,完毕后显示到imageview上. 第一部分:布局文件activity_main.xml < ...
- 微信小程序多图上传/朋友圈传图效果【附完整源码】
效果图 部分源代码 js文件: var uploadPicture = require('../Frameworks/common.js') //获取应用实例 const app = getApp() ...
随机推荐
- 理解CAS算法在JAVA中的作用
- 最大公约数gcd、最小公倍数lcm
最大公约数(辗转相除法) 循环: int gcd(int a,int b) { int r; ) { r=b%a; b=a; a=r; } return b; } 递归: int gcd(int a, ...
- Linked List-3
第一篇终结Linked List(一).终结Linked List(二)主要讲了单链表的基础知识,接下来的第二篇主要讲一些比较经典的问题. 一.Count() 给一个单链表和一个整数,返回这个整数在链 ...
- 2019 ICPC 银川网络赛 D. Take Your Seat (疯子坐飞机问题)
Duha decided to have a trip to Singapore by plane. The airplane had nn seats numbered from 11 to nn, ...
- 线性回归 - LinearRegression - 预测糖尿病 - 量化预测的质量
线性回归是分析一个变量与另外一个或多个变量(自变量)之间,关系强度的方法. 线性回归的标志,如名称所暗示的那样,即自变量与结果变量之间的关系是线性的,也就是说变量关系可以连城一条直线. 模型评估:量化 ...
- E. Count The Blocks
E. Count The Blocks 这是一个计数题,又把我卡自闭了...之前也碰到过类似的题目,这次居然还没有写出来,感觉自己还是太菜了,加油补题吧. 题目大意: 给你一个数字 \(n\),代表的 ...
- java基础篇 之 super关键字的理解
之前一直认为,super指向的是父类对象.到今天,仔细查询了资料,自己做了实验,确认这个结论是不对的.我们分一下几个点讨论下: super的作用: 第一种:用来访问父类被隐藏的成员变量 第二种:用 ...
- Mybatis使用ResultMap
解决字段名和属性名不一致的问题 - 新建数据库表的字段-这里就不贴上了 在下面链接有 https://www.cnblogs.com/rzkwz/p/12853899.html 设置实体类和数据库字段 ...
- python 矢量数据转栅格数据
from osgeo import gdal,osr,ogr#定义投影sr = osr.SpatialReference('LOCAL_CS["arbitrary"]')#在内存中 ...
- LeetCode--Unique Morse Code Words && Flipping an Image (Easy)
804. Unique Morse Code Words (Easy)# International Morse Code defines a standard encoding where each ...