前言
有限状态机(英语:finite-state machine,縮寫:FSM)又稱有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。(FROM WIKI)
FSM的核心和作用
状态机中的核心内容:有限个状态、通过外部操作引起状态的转移。
用来对状态的流转进行解耦,使代码逻辑更加清楚和更容易维护
FSM的组成和分类
组成
- 现态:是指当前所处的状态。
- 条件:又称为事件。当一个条件被满足,可能将会触发一个动作,或者执行一次状态的迁移。
- 动作:条件满足后执行的动作行为。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
- 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
所有的状态转换都可以概括为:F(S, E) -> (A, S’),即如果当前状态为S,接收到一个事件E,则执行动作A,同时状态转换为下个状态S’。
分类
- F(S) -> (A, S’) 型状态机:下一状态只由当前状态决定
- F(S, E) -> (A, S’) 型状态机:下一状态不但与当前状态有关,还与当前输入值有关
通过映射表实现状态机
动作接口:
public interface Action {
boolean action(Context context);
}
映射表数据结构:
@Setter
@Getter
public class ActionMapping {
/**
* 当前状态
*/
private State currentState;
/**
* 次态
*/
private State nextState;
/**
* 动作
*/
private Action action;
/**
* 事件
*/
private Event event;
public static ActionMapping ofMap(State currentState, Event event, State nextState, Action action) {
return new ActionMapping(currentState, event, nextState, action);
}
private ActionMapping(State currentState, Event event, State nextState, Action action) {
this.currentState = currentState;
this.nextState = nextState;
this.action = action;
this.event = event;
}
}
动作中需要使用的上下文参数:
@Getter
@Setter
@AllArgsConstructor
public class Context {
private String param;
}
事件枚举:
public enum Event {
/**
* 审批通过
*/
APPROVE_PASS,
/**
* 审批拒绝
*/
APPROVE_REFUSED,
/**
* 复核通过
*/
RECHECK_PASS,
/**
* 复核不通过
*/
RECHECK_REFUSED;
}
状态枚举:
public enum State {
/**
* 待审核
*/
APPROVE,
/**
* 拒绝
*/
REFUSED,
/**
* 同意
*/
PASS;
}
状态转移表:
@Setter
@Getter
public class ActionMapping {
/**
* 当前状态
*/
private State currentState;
/**
* 次态
*/
private State nextState;
/**
* 动作
*/
private Action action;
/**
* 事件
*/
private Event event;
public static ActionMapping ofMap(State currentState, Event event, State nextState, Action action) {
return new ActionMapping(currentState, event, nextState, action);
}
private ActionMapping(State currentState, Event event, State nextState, Action action) {
this.currentState = currentState;
this.nextState = nextState;
this.action = action;
this.event = event;
}
}
状态机:
public class Machine {
/**
* 状态转移表
*/
private List<ActionMapping> mappings = new ArrayList<>();
{
//F(APPROVE,APPROVE_PASS)->(PASS,ApprovePassAction)
mappings.add(ActionMapping.ofMap(APPROVE, APPROVE_PASS, PASS, new ApprovePassAction()));
//F(APPROVE,APPROVE_REFUSED)->(REFUSED,ApproveRefusedAction)
mappings.add(ActionMapping.ofMap(APPROVE, APPROVE_REFUSED, REFUSED, new ApproveRefusedAction()));
//F(REFUSED,RECHECK_PASS)->(PASS,RecheckPassAction)
mappings.add(ActionMapping.ofMap(REFUSED, RECHECK_PASS, PASS, new RecheckPassAction()));
//F(REFUSED,RECHECK_REFUSED)->(REFUSED,RecheckRefusedAction)
mappings.add(ActionMapping.ofMap(REFUSED, RECHECK_REFUSED, REFUSED, new RecheckRefusedAction()));
}
public boolean transform(State currentState, Event event, Context context) {
ActionMapping actionMapping = getMapping(currentState, event);
if (null == actionMapping) {
throw new RuntimeException("未找到相应的映射");
}
Action action = actionMapping.getAction();
action.action(context);
return true;
}
private ActionMapping getMapping(State currentState, Event event) {
if (mappings.size() > 0) {
for (ActionMapping n : mappings) {
if (n.getCurrentState().equals(currentState) && n.getEvent().equals(event)) {
return n;
}
}
}
return null;
}
}
审批通过动作的实现:
@Override
public boolean action(Context context) {
System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为通过", context.getParam()));
//TODO 将审批状态更新为已审核通过
return true;
}
}
审批拒绝动作的实现:
public class ApproveRefusedAction implements Action {
@Override
public boolean action(Context context) {
System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为拒绝", context.getParam()));
//TODO 将审批状态更新为审核拒绝
return true;
}
}
复核通过动作的实现:
public class RecheckPassAction implements Action {
@Override
public boolean action(Context context) {
System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为通过", context.getParam()));
//TODO 将审批状态更新为审核通过
return true;
}
}
复核拒绝的动作实现
public class RecheckPassAction implements Action {
@Override
public boolean action(Context context) {
System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为通过", context.getParam()));
//TODO 将审批状态更新为审核通过
return true;
}
}
测试类:
public class Test {
public static void main(String[] args) {
Machine machine = new Machine();
machine.transform(APPROVE,APPROVE_REFUSED,new Context("咲夜"));
machine.transform(REFUSED,RECHECK_REFUSED,new Context("咲夜"));
machine.transform(REFUSED,RECHECK_PASS,new Context("帕秋莉"));
}
}
输出:
squirrel状态机框架
就像松鼠一样,小巧,灵活,智能,警觉和可爱的动物,squirrel基础旨在为企业使用提供轻量级,高度灵活和可扩展,可诊断,易于使用和类型安全的Java状态机实现。
squirrel文档:https://www.yangguo.info/2015/02/01/squirrel/
文档中很多已经介绍的十分清楚明白了,我这里就不做过多赘述,只写一个例子。
事件枚举:
public enum Event {
/**
* 审批通过
*/
APPROVE_PASS,
/**
* 审批拒绝
*/
APPROVE_REFUSED,
/**
* 复核通过
*/
RECHECK_PASS,
/**
* 复核不通过
*/
RECHECK_REFUSED;
}
状态枚举:
public enum State {
/**
* 待审核
*/
APPROVE,
/**
* 拒绝
*/
REFUSED,
/**
* 同意
*/
PASS;
}
上下文参数:
@Getter
@Setter
@AllArgsConstructor
public class Context {
private String param;
}
状态机
package com.lg.state.squirrel;
import com.lg.state.Context;
import com.lg.state.Event;
import com.lg.state.State;
import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine;
import java.text.MessageFormat;
public class StateMachine extends AbstractStateMachine<StateMachine, State, Event, Context> {
private void approvePassAction(State from, State to, Event event, Context context) {
System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为通过", context.getParam()));
//TODO 将审批状态更新为已审核通过
}
private void approveRefusedAction(State from, State to, Event event, Context context) {
System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为拒绝", context.getParam()));
//TODO 将审批状态更新为审核拒绝
}
private void recheckPassAction(State from, State to, Event event, Context context) {
System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为通过", context.getParam()));
//TODO 将审批状态更新为审核通过
}
private void recheckRefusedAction(State from, State to, Event event, Context context) {
System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为不通过", context.getParam()));
//TODO 将审批状态更新为审核不通过
}
}
调用入口示例:
public static void main(String[] args) {
StateMachineBuilder<StateMachine, State, Event, Context> builder =
StateMachineBuilderFactory.create(StateMachine.class, State.class, Event.class, Context.class);
/**
* 状态转移表
*/
//F(APPROVE,APPROVE_PASS)->(PASS,approvePassAction)
builder.externalTransition().from(APPROVE).to(PASS).on(APPROVE_PASS).callMethod("approvePassAction");
//F(APPROVE,APPROVE_REFUSED)->(REFUSED,ApproveRefusedAction)
builder.externalTransition().from(APPROVE).to(REFUSED).on(APPROVE_REFUSED).callMethod("approveRefusedAction");
//F(REFUSED,RECHECK_PASS)->(PASS,RecheckPassAction)
builder.externalTransition().from(REFUSED).to(PASS).on(RECHECK_PASS).callMethod("recheckPassAction");
//F(REFUSED,RECHECK_REFUSED)->(REFUSED,RecheckRefusedAction)
builder.externalTransition().from(REFUSED).to(REFUSED).on(RECHECK_REFUSED).callMethod("recheckRefusedAction");
StateMachine machine = builder.newStateMachine(APPROVE);
Context patchouli = new Context("patchouli");
Context xiaoye = new Context("咲夜");
machine.start();
//patchouli审批拒绝
machine.fire(APPROVE_REFUSED,patchouli);
//xiaoye复核成功
machine.fire(RECHECK_PASS,xiaoye);
}
结果: