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系列——状态机(附完整源码)的更多相关文章

  1. 在WebBrowser中执行javascript脚本的几种方法整理(execScript/InvokeScript/NavigateScript) 附完整源码

    [实例简介] 涵盖了几种常用的 webBrowser执行javascript的方法,详见示例截图以及代码 [实例截图] [核心代码] execScript方式: 1 2 3 4 5 6 7 8 9 1 ...

  2. 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件)

    单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 说实话很不想写这篇文章,因为这和我一贯推崇的最好全部编译并使用w ...

  3. 单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)

    单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件) webrtc的音频处理模块分为降噪ns,回音消除aec,回声 ...

  4. 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件)

    webrtc的音频处理模块分为降噪ns和nsx,回音消除aec,回声控制acem,音频增益agc,静音检测部分.另外webrtc已经封装好了一套音频处理模块APM,如果不是有特殊必要,使用者如果要用到 ...

  5. 基于spring-boot和docker-java实现对docker容器的动态管理和监控[附完整源码下载]

    ​ (我是个封面) docker简介 Docker 是一个开源的应用容器引擎,和传统的虚拟机技术相比,Docker 容器性能开销极低,因此也广受开发者喜爱.随着基于docker的开发者越来越多,doc ...

  6. Android自定义组合控件详细示例 (附完整源码)

    在我们平时的Android开发中,有时候原生的控件无法满足我们的需求,或者经常用到几个控件组合在一起来使用.这个时候,我们就可以根据自己的需求创建自定义的控件了,一般通过继承View或其子类来实现. ...

  7. .NET Core中JWT+Auth2.0实现SSO,附完整源码(.NET6)

    一.简介 单点登录(SingleSignOn,SSO) 指的是在多个应用系统中,只需登录一次,就可以访问其他相互信任的应用系统. JWT Json Web Token,这里不详细描述,简单说是一种认证 ...

  8. Java导出Excel(附完整源码)

    导出excel是咱Java开发的必备技能啦,之前项目有这个功能,现在将其独立出来,分享一下.所用技术就是SpringBoot,然后是MVC架构模式.废话不多说,直接上代码了,源码点末尾链接就可以下载. ...

  9. Android静态图片人脸识别的完整demo(附完整源码)

    Demo功能:利用android自带的人脸识别进行识别,标记出眼睛和人脸位置.点击按键后进行人脸识别,完毕后显示到imageview上. 第一部分:布局文件activity_main.xml < ...

  10. 微信小程序多图上传/朋友圈传图效果【附完整源码】

    效果图 部分源代码 js文件: var uploadPicture = require('../Frameworks/common.js') //获取应用实例 const app = getApp() ...

随机推荐

  1. Modbus TCP协议说明

    协议帧 事物处理标识| 协议标识| 长度| 从机地址| 功能码| 数据 0x00 00| 0x00 00| 0x00 08| 0x01| 0x0F| 0x00 14 0x00 01 0x01 0x01 ...

  2. Shiro踩坑记(二):使用RequiresXXX的注解后,访问对应请求返回404

    问题描述: 我在项目中的某个Controller上添加了@RequirePermissions注解,希望在执行该请求前,可以先进行权限验证.但是当我请求该Controller时,返回的确是404错误. ...

  3. BeanDefinition源码解析

    我们知道BeanDefintion定义了Bean在IoC容器内的基本数据结构.在学习IoC之前先了解BeanDefition对我们理解IoC容器是有帮助的. 首先BeanDefinition是一个接口 ...

  4. JAVA学习之路 (五) 类

    java类的学习 先上一个代码 package bankCard; import java.util.Scanner; // 银行卡类 public class bankCard { // 静态变量 ...

  5. MySQL数据库的套接字文件和pid文件

    MySQL数据库的套接字文件和pid文件 socket文件:当用Unix域套接字方式进行连接时需要的文件. pid文件:MySQL实例的进程ID文件. MySQL表结构文件:用来存放MySQL表结构定 ...

  6. 墨仓式进入2.0时代?爱普生商用墨仓式L4158试用

    提起"墨仓式"打印机,相信现在已经没有人需要过多的解释,墨仓式打印机在打印市场占有率不断提高就是最佳佐证.为什么用户对于墨仓式这么认可,想必是墨仓式真正洞悉了他们的需求,解决了打印 ...

  7. 图论--树的重心(DFS) 模板

    const int maxn=500005; int tot=0,n; int ans,size; int sx[maxn],head[maxn]; int vis[maxn]; struct edg ...

  8. USB设备驱动模型

    嵌入式设备驱动的编写,基本上都要按照一定的驱动模型编写.不这么做的话,一旦设备发生了更新和改变,大部分的驱动代码都要推倒重来,代码的重用率低,不具备移植性.所以在新版linux2.6.22以后的内核版 ...

  9. Spring依赖注入—@Resource注解使用

    1.@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowire ...

  10. 1) drf 整体了解

    一.接口 """ 1.什么是接口:url+请求参数+响应数据 | 接口文档 ​ 2.接口规范: url:https,api,资源(名词复数),v1,get|post表示操 ...