文章目录
听到这个名词一愣,但是很快反应过来了,就是状态和逻辑控制名词化了。
当然,和普通逻辑相比,可不是改个名字而已,有很多不同。
什么是状态机
Java状态机是一种用于描述系统状态转换的模型,通过定义状态、事件、动作和转换规则来控制程序行为。
其核心要素如下:
**状态(States):**系统可能处于的固定状态,如订单状态中的"已支付"、"已发货"等 。
**事件(Events):**触发状态转换的外部或内部信号,如"支付"、"取消"等操作 。
**动作(Actions):**状态转换时执行的操作,例如更新状态字段或记录日志 。
**转换(Transitions):**定义事件触发下状态转移的规则,例如"支付成功"事件将"待支付"状态转为"支付成功"。
这么看是否还得维护个状态表,看起来才比较清楚。
普通逻辑和状态机的区别
| 名称 | 普通逻辑 | 状态机 |
|---|---|---|
| 逻辑清晰度 | 需要if else来实现逻辑判断,可读性差 | 状态机通过预定义状态和事件,将状态转换规则显式化,避免冗余的条件判断,可读性强。 |
| 扩展性 | 需要在原代码上修改逻辑,易出错,扩展性差。 | 新增状态或事件时,只需扩展状态机配置,无需修改现有代码。 |
| 线程安全支持 | 需手动处理同步问题(如使用synchronized或Lock),实现复杂且易出错。 | 状态机框架(如Spring StateMachine)内置线程同步机制,确保并发场景下状态一致性。 |
| 业务解耦 | 状态处理常耦合在业务方法内,难以独立测试。 | 状态机将状态逻辑与业务代码分离,便于测试和复用。 |
| 可视化配置 | 普通逻辑需通过代码硬编码状态转换,可读性差。 | 框架支持通过代码或配置文件定义状态机,直观展示状态迁移路径。 |
集成及使用
引入maven依赖
xml
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<!-- uml to code -->
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-uml</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
定义状态枚举
代码:
java
public enum States {
UNPAID, // 待支付
WAITING_FOR_RECEIVE, // 待收货
DONE // 结束
}
定义事件枚举
代码:
java
public enum Events {
PAY, // 支付
RECEIVE // 收货
}
初始化订单的状态集合以及状态转移事件
代码:
java
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {
private Logger LOGGER = LoggerFactory.getLogger(getClass());
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states.withStates().initial(States.UNPAID).states(EnumSet.allOf(States.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.UNPAID).target(States.WAITING_FOR_RECEIVE)
.event(Events.PAY)
.and()
.withExternal()
.source(States.WAITING_FOR_RECEIVE).target(States.DONE)
.event(Events.RECEIVE);
}
//守护
@Bean
public Guard<States, Events> guard() {
return new Guard<States, Events>() {
public boolean evaluate(StateContext<States, Events> context) {
return true;
}
};
}
状态转移的监听器
java
@WithStateMachine
public class EventListener {
private Logger LOGGER = LoggerFactory.getLogger(getClass());
@OnTransition(target = "UNPAID")
public void create() {
//此处可以执行具体业务逻辑处理
LOGGER.info("--------------------订单创建,待支付-----------------------");
}
@OnTransition(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
public void pay() {
//此处可以执行具体业务逻辑处理
LOGGER.info("--------------------用户完成支付,待收货--------------------");
}
@OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
public void receive() {
//此处可以执行具体业务逻辑处理
LOGGER.info("--------------------用户已收货,订单完成----------------------");
}
}
测试
测试类代码:
java
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
@Test
public void contextLoads() {
}
@Autowired
private StateMachine<States, Events> stateMachine;
@Test
public void test() throws Exception {
stateMachine.start();
stateMachine.sendEvent(Events.PAY);
stateMachine.sendEvent(Events.RECEIVE);
}
}
1.只运行启动
java
@Test
public void test() throws Exception {
stateMachine.start(); //springboot启动时开启 待支付
//stateMachine.sendEvent(Events.PAY); //支付操作 待收货
//stateMachine.sendEvent(Events.RECEIVE); //收货操作 结束
}
2.运行启动与支付操作
java
@Test
public void test() throws Exception {
stateMachine.start(); //springboot启动时开启 待支付
//stateMachine.sendEvent(Events.PAY); //支付操作 待收货
//stateMachine.sendEvent(Events.RECEIVE); //收货操作 结束
}
3.全部执行
java
@Test
public void test() throws Exception {
stateMachine.start(); //springboot启动时开启 待支付
stateMachine.sendEvent(Events.PAY); //支付操作 待收货
stateMachine.sendEvent(Events.RECEIVE); //收货操作 结束
}