概念
状态机
(State Machine)是一种用于描述系统在不同状态下的行为及状态之间转换的数学模型。状态机主要由三个部分组成:状态
(State)、事件
(Event)和转换
(Transition)。
- 状态(State):状态表示系统在特定时刻的条件或情况。一个状态机可以有多个状态,但在任意时刻,系统只能处于一个状态。
- 事件(Event):事件是导致状态之间转换的触发器。事件可以是外部输入,也可以是系统内部发生的事情。当事件发生时,系统可能会从当前状态转换到另一个状态。
- 转换(Transition):转换表示系统从一个状态到另一个状态的过程。转换通常会有一些条件或动作与之关联。条件表示在满足特定条件时才会发生状态转换,而动作表示在状态转换过程中执行的操作。
相关资料👉:有限状态机 - 维基百科,自由的百科全书 (wikipedia.org)
相关图示
如下图所示,整个状态机包含5个节点,每个节点都有自己对应的逻辑,每个节点都可能执行多次
示例代码
下面代码为上面图片的参考demo代码
//状态枚举
enum StateEnum {
//定义开始节点以及结束节点,便于状态流转控制
Start("doProcessA", new DoProcessA()),
ProcessB("doProcessB", new DoProcessB()),
ProcessC("doProcessC", new DoProcessC()),
ProcessD("doProcessD", new DoProcessD()),
End("", null);
private String stateClassName;
private State state;
StateEnum(String stateClassName, State doProcessAClass) {
this.stateClassName = stateClassName;
this.state = doProcessAClass;
}
public String getStateClassName() {
return this.stateClassName;
}
public void setStateClassName(final String stateClassName) {
this.stateClassName = stateClassName;
}
public State getState() {
return this.state;
}
public void setState(final State state) {
this.state = state;
}
}
//状态信息上下文
class StateContext {
private List<String> processList;
private static Map<String, State> statesMap = new ConcurrentHashMap<>();
/**
* 创建上下文
* @return
*/
public static StateContext createStateContext() {
StateContext stateContext = new StateContext();
stateContext.setProcessList(new ArrayList<>());
return stateContext;
}
/**
* 获取具体状态执行器
* @param name
* @return
*/
public static State getStateByName(StateEnum name) {
if (statesMap.size() == 0) {
for (StateEnum value : StateEnum.values()) {
if (!StateEnum.End.equals(value)){
statesMap.put(value.getStateClassName(), value.getState());
}
}
}
if (StateEnum.End.equals(name)) {
return null;
} else {
return statesMap.get(name.getStateClassName());
}
}
public List<String> getProcessList() {
return this.processList;
}
public void setProcessList(final List<String> processList) {
this.processList = processList;
}
}
//抽象状态节点接口
interface State {
void doProcess(StateContext stateContext);
StateEnum nextState(StateContext stateContext);
}
//具体状态实现节点DoProcessA、DoProcessB、DoProcessC、DoProcessD
class DoProcessA implements State{
@Override
public void doProcess(StateContext stateContext) {
System.out.println("processing A...");
List<String> processList = stateContext.getProcessList();
processList.add("process a");
System.out.println("current processList:" + processList);
}
@Override
public StateEnum nextState(StateContext stateContext) {
return StateEnum.ProcessB;
}
}
class DoProcessB implements State{
@Override
public void doProcess(StateContext stateContext) {
System.out.println("processing B...");
List<String> processList = stateContext.getProcessList();
processList.add("process b");
System.out.println("current processList:" + processList);
}
@Override
public StateEnum nextState(StateContext stateContext) {
//处理分支分叉
if (null != stateContext.getProcessList() && stateContext.getProcessList().size() <= 3){
return StateEnum.ProcessD;
}
return StateEnum.ProcessC;
}
}
class DoProcessC implements State{
@Override
public void doProcess(StateContext stateContext) {
System.out.println("processing C...");
List<String> processList = stateContext.getProcessList();
processList.add("process c");
System.out.println("current processList:" + processList);
}
@Override
public StateEnum nextState(StateContext stateContext) {
return StateEnum.End;
}
}
class DoProcessD implements State{
@Override
public void doProcess(StateContext stateContext) {
System.out.println("processing D...");
List<String> processList = stateContext.getProcessList();
processList.add("process d");
System.out.println("current processList:" + processList);
}
@Override
public StateEnum nextState(StateContext stateContext) {
return StateEnum.ProcessB;
}
}
//测试demo
public class StateTest {
public static void main(String[] args) {
StateContext stateContext = StateContext.createStateContext();
//定义开始节点
StateEnum stateEnum = StateEnum.Start;
State state = StateContext.getStateByName(stateEnum);
do {
//处理业务
state.doProcess(stateContext);
//设置下一个状态节点
StateEnum nextStateEnum = state.nextState(stateContext);
state = StateContext.getStateByName(nextStateEnum);
//节点执行到结束节点后,状态机停止运行
}while (!StateEnum.End.equals(stateEnum) && null != state);
System.out.println("process end");
}
}
运行结果
状态机适用场景
状态机在处理具有复杂状态转换逻辑的场景时非常有用。以下是一些适用状态机的典型场景:
- 游戏开发:在游戏中,角色和对象可能有多种状态,如站立、移动、攻击等。使用状态机可以轻松地管理这些状态之间的转换和相关行为。
- 工作流引擎:工作流引擎需要处理业务流程中的多个步骤和状态,状态机可以帮助管理这些步骤之间的转换。
- 通信协议:在通信协议中,连接可能有多个状态,如建立、断开、重新连接等。状态机可以帮助实现协议的状态管理。
- 用户界面:在用户界面中,控件可能有多个状态,如激活、禁用、聚焦等。状态机可以使界面状态管理更加简洁和清晰。
- 自动售货机:自动售货机需要处理不同状态下的用户输入,如投币、选择商品、退币等。状态机可以有效地管理这些状态及其之间的转换。
- 有限状态自动机(Finite State Automata):在计算机科学中,有限状态自动机是一种理论模型,用于表示和分析具有有限状态集的离散时间系统。它在正则表达式、词法分析器、解析器等领域中有广泛应用。
状态机适用于那些具有多个状态及状态之间存在复杂转换关系的场景。通过使用状态机,可以将复杂的逻辑分解为多个简单的状态,使代码更加易于理解和维护。