在日常开发中,你是否会遇到过“状态流转”的代码?例如订单状态的变化流程,从“提交”到“支付”,“配送中”,“收货”。怎么写这些代码才能够易于维护和扩展?使用状态模式和Spring的状态机或许能帮助你。来看看这篇文章,应该有所收获。
在下手写代码前,估计你会画一张状态变更的“流程图”(或者叫有限状态机),本文假设一个交易需要经过的状态如下:【初始化->草稿->等待审批->取消或者完成】
在没有了解状态模式之前,设想一下,我们会怎么写代码,可能会把所有的事件写在一个大的switch里,然后根据不同的状态进行不同的处理,这样我们在修改状态的业务逻辑或者增加状态的时候,需要修改同一个switch下的代码,然后进行回归测试,类似以下:
private
稍微改进一下,单独为每个事件实现一个方法,类似以下:
private
这样写每个事件相对独立,不过要新增事件和状态的时候需要新增方法,之后进行回归测试。并且这两种写法都有同样的问题,状态的变化与业务逻辑纠缠在一起,并且状态变化流程并不清晰,如将来需要增加新的状态,将难以扩展。例如我们现在需要需要增加一个“等待验证”的状态(如下图红色部分),我们得把真个流程的代码都小心理解透了,才知道在哪里“塞”进去这一块。
看看“状态模式”是如何帮助我们的:
首先有一个状态机状态接口(MachineState),包含每个状态都有的抽象方法(processBusinessLogic),每个状态都是一个类,实现MachineState的抽象方法。这样使每个状态解耦,新增一个状态也不必修改原有的代码(符合开闭原则)。另外一个状态机类(StateMachine)负责持有这些状态的聚合并且负责状态的变更流转,把状态变更和业务代码做解耦。这样说毕竟苍白,来看看代码怎么写:
public
我们平时在做web开发的过程中,保证每次请求都是“无状态”(stateless)的很重要,可是状态机的运转是要保证有状态的,怎么做到状态机的持久化?如果遇到多线程的状态要处理怎么办?幸好Spring Statemachine项目都为我们想好了。先从最简单的实现状态机开始:
步骤一:配置spring状态机
@Configuration
步骤二:配置监听器,每个事件触发的业务逻辑写在这里
@Component
步骤三:启动spring进行测试
@SpringBootApplication
在实际项目中,需要持久化状态机的状态,可以使用mysql或者redis来存储。文中的所有代码都已经上传到github,以下是项目链接:
chenkaijiekidd/state-machinegithub.comSpring statemachine的项目地址:
Spring Statemachineprojects.spring.io希望这篇文章能帮助你,有任何疑问可以评论,我也会一一回答。Spring Statemachine希望这篇文章能帮助你,有任何疑问可以评论,我也会一一回答。