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

这篇具有很好参考价值的文章主要介绍了还在用ifelse来写业务?了解下Spring状态机。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

什么是状态

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

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

什么是状态机

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

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

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

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

graph LR A[小马里奥] -->|吃蘑菇| B[超级马里奥] B -->|吃花| C[火焰马里奥] C -->|被敌人碰到| B B -->|被敌人碰到| A

与状态设计模式的区别

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

在状态设计模式中,每个状态是一个单独的类实例,这些类通常会实现一个公共接口,以便上下文对象可以调用适当的方法,而无需知道具体当前处于哪种状态。上下文对象(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 StateMachineConfig
        extends EnumStateMachineConfigurerAdapter<States, Events> {

    /**
     * 配置状态机的全局属性,如自动启动和状态监听器。
     *
     * @param config 状态机配置构建器
     * @throws Exception 如果配置过程中发生错误
     */
    @Override
    public void configure(StateMachineConfigurationConfigurer<States, Events> config)
            throws Exception {
        config
                .withConfiguration()
                .autoStartup(true) // 设置状态机自动启动
                .listener(listener()); // 注册状态改变监听器
    }

    /**
     * 配置状态机的状态。
     *
     * @param states 状态配置构建器
     * @throws Exception 如果配置过程中发生错误
     */
    @Override
    public void configure(StateMachineStateConfigurer<States, Events> states)
            throws Exception {
        states
                .withStates()
                .initial(States.SI) // 设置初始状态为SI
                .states(EnumSet.allOf(States.class)); // 将所有枚举状态添加到状态机
    }

    /**
     * 配置状态机的转换。
     *
     * @param transitions 转换配置构建器
     * @throws Exception 如果配置过程中发生错误
     */
    @Override
    public 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 状态机监听器实例
     */
    @Bean
    public StateMachineListener<States, Events> listener() {
        return new StateMachineListenerAdapter<States, Events>() {
            @Override
            public 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{
    @Autowired
    private StateService stateService;

    @GetMapping(value = "改变状态")
    @Operation(description = "改变状态")
    public void change() {
        stateService.changeState();
    }
}
/**
 * 状态机演示服务
 */
@Service
public class StateService {
    @Autowired
    private 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(备注技术)。文章来源地址https://www.toymoban.com/news/detail-840310.html

到了这里,关于还在用ifelse来写业务?了解下Spring状态机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 大厂一线研发揭秘:怎么样才算全面了解了业务?

    大厂一线研发揭秘:怎么样才算全面了解了业务?

    刚做开发时,觉得自己要好好学习技术,对业务不上心,公司让我做什么就用自认为极其优雅的编码方式解决,但对为什么要做这个事,做了对业务有什么影响,做完了有没有达到业务目标,并没有很关心。后续观察了身边的一些同学,整体上业务与技术链接比较好的同学职

    2024年04月22日
    浏览(5)
  • 突破传统监测模式:业务状态监控HM的新思路 | 京东云技术团队

    突破传统监测模式:业务状态监控HM的新思路 | 京东云技术团队

    在系统架构设计中非常重要的一环是要做数据监控和数据最终一致性,关于一致性的补偿,已经由算法部的大佬总结过就不再赘述。这里主要讲如何去补偿?补偿的方案哪些?这就引出来数据监控系统了。有小伙伴会问了,为什么业务状态监控系统可以做补偿?别急,往下看

    2024年02月14日
    浏览(5)
  • 认识http的方法、Header、状态码以及简单实现一个http的业务逻辑

    认识http的方法、Header、状态码以及简单实现一个http的业务逻辑

    方法 说明 支持的HTTP版本 GET 获取资源 1.0/1.1 POST 传输实体主体 1.0/1.1 PUT 传输文件 1.0/1.1 HEAD 获得报文首部 1.0/1.1 DELETE 删除文件 1.0/1.1 OPTIONS 询问支持方法 1.1 TRACE 追踪路径 1.1 CONNECT 要求用隧道协议连接代理 1.1 LINK 建立和资源之间的联系 1.0 UNLINE 断开连接关系 1.0 其中最为常见

    2024年02月13日
    浏览(8)
  • Web 攻防之业务安全:Response状态值修改测试(修改验证码返回值 绕过限制.)

    业务安全是指保护业务系统免受安全威胁的措施或手段。 广义 的业务安全应包括业务运行的 软硬件平台 (操作系统、数据库,中间件等)、 业务系统自身 (软件或设备)、 业务所提供的服务安全 ; 狭义 的业务安全指 业务系统自有的软件与服务的安全 。 Response状态值修

    2023年04月16日
    浏览(5)
  • MVC、MVP、MVVM的成本角度结合业务,如何考虑选型?一文了解方方面面

    MVC、MVP、MVVM的成本角度结合业务,如何考虑选型?一文了解方方面面

    大家都知道,使用架构的目的是使程序模块化,做到模块内部的高聚合和模块之间的低耦合,使得程序在开发的过程中,开发人员只需要专注于一点,提高程序开发的效率。那么MVC、MVP、MVVM,该怎么选?在什么最省去开发时间和业务成本? 本篇来彻底理解MVC、MVP、MVVM这三个

    2024年02月10日
    浏览(11)
  • Spring高手之路-Spring在业务中常见的使用方式

    目录 通过IOC实现策略模式 通过AOP实现拦截增强 1.参数检验 2.缓存逻辑 3.日志记录 通过Event异步解耦 通过Spring管理事务 1.声明式事务 2.编程式事务 3.需要注意的问题 不能在事务中处理分布式缓存 不能在事务中执行 RPC 操作 不过度使用声明式事务 很多时候,我们需要对不同的

    2024年01月19日
    浏览(8)
  • 使用AI来写PPT

    使用AI来写PPT

    最近工作中经常会写各种各样的ppt,选版图选格式,写文字非常费时。 发现一款协助写ppt的服务,对不喜欢写ppt的人非常友好,如果对效果要求不高,基本1分钟一个成品ppt。Aippt网址:https://www.aippt.cn/ 一、进入选择  二、选择智能生成ppt 三、如果有word的提纲(也就是所谓的

    2024年01月19日
    浏览(4)
  • JavaEE 初阶篇-深入了解多线程等待与多线程状态

    JavaEE 初阶篇-深入了解多线程等待与多线程状态

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 线程等待         1.1 线程等待 - join() 方法         1.1.1 main 线程中等待多个线程         1.1.2 main 线程等待 t2 线程且t2 线程等待 t1 线程         1.1.3 其他线程阻塞等待 main 线程

    2024年04月17日
    浏览(5)
  • 【Spring Boot】service 业务层简单使用

    【Spring Boot】service 业务层简单使用

    在controller同级目录下创建service 在controller里出入service

    2024年04月12日
    浏览(9)
  • Python来写一个童话故事

    Python来写一个童话故事

    主题:冒险, 风格:惊险, 人物:男孩, 地点:海底。 def move_left(): # 获取男孩当前的x坐标,并减去男孩的速度,得到新的x坐标 x = boy.xcor() - BOY_SPEED # 如果新的x坐标小于屏幕左边界加上男孩的大小的一半,则将新的x坐标设置为屏幕左边界加上男孩的大小的一半,防止男孩

    2024年02月06日
    浏览(10)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包