Java有限状态机FSM(基础篇)
前言
在java后端项目的开发过程中,经常会碰到需要进行状态转换的场景,比如订单的状态、任务的状态等等,通常会使用枚举对状态进行定义,并在需要时更改其枚举值。
但是在一些比较复杂的场景下,例如状态数大于等于5个,或者大状态拥有子状态的场景(如订单【交易中】的状态包含【待发货】【已发货】等子状态),再直接通过修改枚举值的方式已经难以进行维护,且会导致状态变更的代码在项目中散布,不仅在实现上不够优雅,而且在需要添加或者修改状态时牵一发而动全身。因此,我们需要有一种技术手段,来对状态进行统一管理,以及收束变更状态的代码入口。
有限状态机(Finite State Machine, FSM)就是用来干这个事的!
该文是一个系列文章,本章先介绍基本概念及其简单实现
状态机就是包含多个状态的数学模型,并可以在状态之间进行变换并且触发一些动作。
一个状态机一般包含以下几个元素
State当前状态Event触发事件Transition状态变换,或者说下一个状态(次态)Action要执行的动作
如何实现一个简单的状态机
这里根据多篇参考文档,总结以下四种实现方式并进行简述,具体的实现代码可以查看参考文档2
1. switch...case
- 保存当前状态
- 状态变更时传入变更事件event, 先通过
if...else判断是哪个事件,再对当前事件event进行switch...case确定要执行的操作 - 进入下一个状态,并执行
action
简单代码如下
public class StateMachine {
// 当前状态
private State currState;
public StateMachine(State initState) {
this.currState = initState;
}
public void transist(Event event) {
if (当前是状态1) {
switch (event) {
case 事件1:
// 设置下一个状态
// 执行action
case 事件2:
...
}
}
// ......
}
}
该种方法实现是最简单的实现方法,在状态数量较少时,这是一个很高效的实现方案。但是在较复杂的状态下,会导致嵌套大量的 if...else 和 switch...case 语句,维护起来费劲而且实现不够优雅。
2. 状态模式 (State Design Pattern)
状态模式主要就是对转换规则进行封装,封装状态而暴露行为,状态的改变看起来就是行为发生改变,总结起来,状态模式干了这么几件事
需要定义状态抽象类 AbstractState,其中需要包含上下文 Context, 以及所有的抽象事件(event)对象的方法
public abstract class AbstractState {
// 上下文信息
protected Context context;
public void setContext(Context context) {
this.context = context;
}
// 事件操作放在具体的状态定义内
abstract void event1();
abstract void event2();
// ...... }
具体的状态需要继承并实现抽象状态
public class State1 extends AbstractState {
@Override
void event1() {
// set next state
// do something else
}
// ......
}
上下文 Context 中需要包含所有所需信息,包括所有的状态实例,并指定一个属性指示当前是哪个状态实例
public class Context {
// 当前状态实例
protected AbstractState currState;
protected static final State1 state1 = new State1();
protected static final State2 state2 = new State2();
// ......
public Context(AbstractState state) {
setState(state);
}
// 具体的事件调用当前状态进行执行
public void event1(){
this.currState.event1();
}
// ......
}
由上可见,状态模式将与行为与状态相绑定,避免了直接去写大量的 if...else 和 switch...case 编写时可以方便地增加新的状态,并且只需要改变对象的状态就可以改变对象的行为。、
参考: