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() ...
随机推荐
- qemu-img 整理
qemu-img命令语法: qemu-img command [command options] check命令: check [-f fmt < qcow2 | qed | vdi >] ...
- Eclipse Mac OS 安装 Subversion插件subclipse 缺失JavaHL解决方案
安装 SVN 插件 subclipse 时可能遇到问题 subclipse 安装完成后,当我们选择使用 的时候还是会提示:javaHL not available, SVN接口选择 client:选择 ...
- Spring MVC之LocaleResolver详解
2019独角兽企业重金招聘Python工程师标准>>> 对于LocaleResolver,其主要作用在于根据不同的用户区域展示不同的视图,而用户的区域也称为Locale,该信息是可以 ...
- Linux运维面试题:请简要说明Linux系统在目标板上的启动过程?
Linux运维面试题:请简要说明Linux系统在目标板上的启动过程? 该问题是Linux运维面试最常见的问题之一,问题答案如下: 1.用户打开PC的电源,BIOS开机自检,按BIOS中设置的启动设备( ...
- 4.shell基本操作简介
判断一个命令是不是内置命令,可以用type命令 1.printf :冒号 #:〉 test.txt 这里会建立一个空文件test.txt set -o|grep emacs 查看 emacs 模式是 ...
- mysql查询语句中like 的用法
1.常见用法: (1)搭配%使用 %代表一个或多个字符的通配符,譬如查询字段name中以大开头的数据: (2)搭配_使用 _代表仅仅一个字符的通配符,把上面那条查询语句中的%改为_,会发现只能查询出一 ...
- postman(全局变量设置)
全局变量 全局变量作用于整个postman工具及所有环境 1.点击小齿轮进入到变量添加页面,点击Globals添加全局变量 2.输入变量名称和变量值 3.接口中设置变量 4.调用 Globals 变量 ...
- js怎么删除数组元素,有哪些删除元素方法
JavaScript删除元素方法 1.根据索引删除数组元素 delete 数组[索引] *注意delete 后面是空格 var arr1=["aa","bb" ...
- M - Little Pony and Harmony Chest 状压dp
M - Little Pony and Harmony Chest 怎么感觉自己越来越傻了,都知道状态的定义了还没有推出转移方程. 首先这个a的范围是0~30 这里可以推出 b数组的范围 0~60 ...
- jQuery中bind()与on()绑定事件的区别
.on()方法比.bind()方法多一个参数selector .on()的selector参数是筛选出调用.on()方法的dom元素的指定子元素,如: $("ul").on('cl ...