还在用ifelse来写业务?了解下Spring状态机

2024-03-15 16:44

本文主要是介绍还在用ifelse来写业务?了解下Spring状态机,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

状态机之所以强大,是因为其行为在启动时就以固定的方式定义了操作规则,从而确保了一贯的连贯性和相对较高的可调试性。关键在于,应用程序处于且仅可能处于有限数量的状态中。然后,某些事件发生会使得应用从一个状态过渡到另一个状态。状态机由触发器驱动,这些触发器基于事件或计时器。

设计高层次逻辑并将其置于应用程序外部,然后通过多种方式与状态机交互,这种方式要简单得多。可以通过发送事件、监听状态机的行为或请求当前状态来与状态机进行交互。

当开发者意识到代码库开始变得般混乱不堪时,就会在现有项目中引入状态机。面条代码表现为无尽的、层级化的IF、ELSE和BREAK子句结构,当事情变得过于复杂时,编译器或许应该建议开发者暂停一下,先休息一下。状态机的引入有助于将复杂多变的应用程序状态转换过程组织得更为有序和清晰,从而避免代码陷入难以维护的境地。

什么是状态

状态是状态机可能处于的一种模型。相比于在通用文档中使用抽象概念,通过现实生活中的例子来描述状态通常更为直观易懂。以一个简单的键盘为例——我们大多数人每天都使用它。如果你有一个标准键盘,左侧有普通键,右侧有数字小键盘,你可能会注意到,根据Numlock(数字锁定)是否激活,数字小键盘可以处于两种不同的状态。如果没有激活,按下数字小键盘的按键会实现方向导航等功能;如果数字小键盘被激活,则按下这些键将输入数字。本质上,键盘的数字小键盘部分可以处于两种不同的状态。

将状态的概念联系到编程上,这意味着我们可以不再依赖于标志位、嵌套的if/else/break语句或其他不切实际(有时甚至是曲折复杂的)逻辑,而是可以通过状态、状态变量或与状态机的交互来处理问题。换句话说,在编程中运用状态这一概念,能够帮助我们更清晰地组织和管理程序的不同状态及其转换过程。

什么是状态机

状态机是一种理论模型,它描述了一个对象在其生命周期内可能经历的有限数量的状态及其之间的转换规则。每个状态都有触发状态迁移的条件(通常是事件),并且可以关联执行的动作。

状态机的核心在于状态变迁和事件驱动,适合处理异步和并发的情况。状态机强调的是系统当前所处的状态,并且关注于系统如何根据接收到的外部事件或内部条件进行状态转变。

状态机最常见于嵌入式系统、用户界面交互设计、游戏开发、网络协议解析等领域。

以下以游戏马里奥的状态切换为例,来理解状态机的使用场景:

吃蘑菇
吃花
被敌人碰到
被敌人碰到
小马里奥
超级马里奥
火焰马里奥

与状态设计模式的区别

在面向对象编程中,状态设计模式是一种行为型设计模式,允许对象在其内部状态改变时改变其行为。该模式通过将每一个状态封装成一个类,使得当对象的状态发生改变时,它的行为也随之改变,同时能够使代码更加清晰和模块化。

在状态设计模式中,每个状态是一个单独的类实例,这些类通常会实现一个公共接口,以便上下文对象可以调用适当的方法,而无需知道具体当前处于哪种状态。上下文对象(context)持有对当前状态对象的引用,并在接收到特定事件时调用状态对象的方法来处理事件并可能导致状态切换。

联系

  • 状态设计模式是对状态机理论的一种实现,它把状态机的概念应用于软件设计中,利用面向对象技术实现了状态的抽象、封装和扩展性。

区别

  • 状态机是一个抽象的概念,可以不依赖于任何特定的编程语言或设计模式独立存在。
  • 状态设计模式则是具体的编程实践,是针对解决状态转换问题的一种设计解决方案,特别适用于面向对象环境下的复杂状态管理。

与流程引擎的区别

**流程引擎(Business Process Management Engine, BPMN Engine)**是实现业务流程管理(BPM)的软件组件,主要用于执行和监控预定义的工作流程。这些工作流程通常包括一系列顺序执行的任务或活动,具有明确的开始点、结束点和中间过程。

流程引擎支持更复杂的流程结构,如并行分支、同步合并、循环等,并提供了丰富的建模语言(如BPMN)来可视化表示流程逻辑。流程引擎不仅关注状态转移,还注重任务分配、资源调度、事务处理以及流程实例的整体生命周期管理。

流程引擎适用于企业级应用中需要自动化、规范化和优化的复杂业务流程,比如采购审批流程、贷款审批流程、订单处理流程等。

区别与联系:

  • 目的性不同: 状态机主要解决状态变化的问题,而流程引擎则更多地关注流程的整体组织和执行。
  • 结构灵活性: 状态机结构相对简单,特别适合清晰、固定的流程;流程引擎支持多层次、多路径的复杂流程,允许动态调整和扩展。
  • 参与角色: 状态机侧重于机器层面的自动化处理,流程引擎则常涉及人的参与决策和协同工作。
  • 集成度: 流程引擎通常包含更多的管理和监控功能,能够与组织其他系统紧密集成,提供强大的审计跟踪、异常处理和数据分析能力。
  • 联系: 在实际项目中,状态机的概念和机制可能会作为流程引擎的一部分被采用,尤其是在流程中有明显的状态变迁环节时。同时,两者都可以用作业务规则和流程规范的有效工具,只不过各自聚焦的领域和复杂程度有所差异。

什么是Spring状态机

Spring Statemachine(SSM)是一个框架,允许应用程序开发者在Spring应用中使用传统的状态机概念。SSM提供了以下功能:

  1. 为简单用例提供易于使用的单层(一级)状态机。
  2. 采用分层状态机结构,便于配置复杂状态。
  3. 状态机区域以支持更为复杂的状态配置。
  4. 支持触发器、转换、守卫和动作的使用。
  5. 提供类型安全的配置适配器。
  6. 集成了状态机事件监听器。
  7. 与Spring IoC(控制反转)集成,可将Bean关联至状态机。

SSM有哪些使用场景

项目适于使用状态机的场景包括:

  1. 当你可以将应用程序或其部分结构表示为一系列状态时,该项目是应用状态机的良好候选者。
  2. 你希望将复杂的逻辑拆分为更小、更易于管理的任务。
  3. 应用程序已经存在并发问题,例如异步操作导致的问题。

在以下情况下,实际上你已经在尝试实现一个状态机:

  1. 使用布尔标志或枚举来模拟各种情况。这意味着你的代码可能在通过这些标志和枚举跟踪不同状态。
  2. 拥有仅在应用程序生命周期中的某些阶段才有意义的变量。这暗示了状态变化对程序流程的影响。
  3. 正在循环遍历if-else结构(或者更糟糕的是,多个这样的结构),检查特定标志或枚举是否已设置,然后根据这些标志和枚举是否存在及其组合进一步判断接下来的操作。这种编程方式本质上是在手动处理状态转移,而采用状态机可以更清晰、规范地表述并简化此类复杂的状态转换逻辑。

如何集成SSM

需要在maven或者gradle中ssm的依赖。

<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-starter</artifactId><version>4.0.0</version>
</dependency>
implementation 'org.springframework.statemachine:spring-statemachine-starter:4.0.0'

如何使用SSM

下面以一个简单的例子来说明如何使用SSM。

// 定义对应状态和事件的枚举:
public enum States {SI, S1, S2
}public enum Events {E1, E2
}// 定义状态机的配置
import java.util.EnumSet;@Configuration // 标识为配置类
@EnableStateMachine // 启用状态机功能
public class StateMachineConfigextends EnumStateMachineConfigurerAdapter<States, Events> {/*** 配置状态机的全局属性,如自动启动和状态监听器。** @param config 状态机配置构建器* @throws Exception 如果配置过程中发生错误*/@Overridepublic void configure(StateMachineConfigurationConfigurer<States, Events> config)throws Exception {config.withConfiguration().autoStartup(true) // 设置状态机自动启动.listener(listener()); // 注册状态改变监听器}/*** 配置状态机的状态。** @param states 状态配置构建器* @throws Exception 如果配置过程中发生错误*/@Overridepublic void configure(StateMachineStateConfigurer<States, Events> states)throws Exception {states.withStates().initial(States.SI) // 设置初始状态为SI.states(EnumSet.allOf(States.class)); // 将所有枚举状态添加到状态机}/*** 配置状态机的转换。** @param transitions 转换配置构建器* @throws Exception 如果配置过程中发生错误*/@Overridepublic void configure(StateMachineTransitionConfigurer<States, Events> transitions)throws Exception {transitions.withExternal() // 配置外部触发的转换.source(States.SI).target(States.S1).event(Events.E1) // 定义从SI到S1的转换,由事件E1触发.and() // 连接另一个转换配置.withExternal() // 另一个外部触发的转换.source(States.S1).target(States.S2).event(Events.E2); // 定义从S1到S2的转换,由事件E2触发}/*** 创建并返回一个状态机监听器,用于监听状态的改变。** @return 状态机监听器实例*/@Beanpublic StateMachineListener<States, Events> listener() {return new StateMachineListenerAdapter<States, Events>() {@Overridepublic void stateChanged(State<States, Events> from, State<States, Events> to) {if(from != null){System.out.println("State change from " + from.getId());}System.out.println("State change to " + to.getId());}};}
}

测试代码如下:

@RestController
@Tag(name = "状态机", description = "状态机")
public class StateController{@Autowiredprivate StateService stateService;@GetMapping(value = "改变状态")@Operation(description = "改变状态")public void change() {stateService.changeState();}
}
/*** 状态机演示服务*/
@Service
public class StateService {@Autowiredprivate StateMachine<States, Events> stateMachine;public void changeState() {stateMachine.sendEvent(Events.E1);stateMachine.sendEvent(Events.E2);}
}

服务层的输出的结果如下:

State change to SI
State change from SI
State change to S1
State change from S1
State change to S2

以上代码只是简单演示了SSM的集成和使用demo。实际业务场景可能更为复杂,需要根据实际需求进行扩展。

除了状态,要更好的使用SSM还需要理解伪状态等很多概念,比如Junction(允许多个传入转换)、 Fork(一个或多个区域的显式入口)、Join (将源自不同区域的多个过渡合并在一起)。这部分内容将在后续文章中进行介绍。

参考

  • A State Machine Crash Course - spring-statemachine https://docs.spring.io/spring-statemachine/docs/4.0.0/reference/index.html#crashcourse

关于作者

来自一线全栈程序员nine的八年探索与实践,持续迭代中。欢迎关注公众号“雨林寻北”或添加个人卫星codetrend(备注技术)。

这篇关于还在用ifelse来写业务?了解下Spring状态机的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/812607

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听