介绍
- 这里特别解释一下为什么说状态机是DSL一种实现。因为要使用状态机,必须要遵循它规定的顺序调用方法,不能随意更改顺序。如同XML那样,每个配置项都是要符合一定的结构顺序才行。只有配置正确了,它的配置项才会生效。
- cola stateMachin是阿里大神开发的无状态状态机,且已经被阿里在生产环境中做了验证。但是它还有很多场景是无法实现的,需要结合我们自己的业务做二次开发。
- 这里重申一下,不是说spring stateMachine 不好,反而是它太好了,好的有点过分。spring stateMachine中有很多优秀的功能,然而这些功能在我们日常开发中,是根本用不到的。导致了spring stateMachine显得太过笨重。
- 代码简单,易于学习,便于结合我们自己的业务做二次开发。
- 无状态,内存消耗少,线程先天安全。
- 先天支持事务。
- 先天会抛出异常,不会出现像spring stateMachine那样将异常吃掉的情况(当然通过反射确实可以将异常抛出)。
- 包小减少资源浪费,摒弃了spring stateMachine中没有必要的功能。
- State:状态
- Event:事件,状态由事件触发,引起变化
- Transition:流转,表示从一个状态到另一个状态
- External Transition:外部流转,两个不同状态之间的流转
- Internal Transition:内部流转,同一个状态之间的流转(不推荐使用,这种情况下会出现状态循环)
- Condition:条件,表示是否允许到达某个状态
- Action:动作,到达某个状态之后,可以做什么
- StateMachine:状态机
INTERNAL --- 内部流转, LOCAL --- 无具体实现, EXTERNAL --- 外部流转, CHOOSE ---自定义新增,
public class StateMachineBuilderFactory { public static <S, E, C> StateMachineBuilder<S, E, C> create(){ return new StateMachineBuilderImpl<>(); } } public class StateMachineBuilderImpl<S, E, C> implements StateMachineBuilder<S, E, C> { /** * StateMap is the same with stateMachine, as the core of state machine is holding reference to states. * 状态枚举持有对状态机的引用 */ private final Map<S, State< S, E, C>> stateMap = new ConcurrentHashMap<>(); /** * 当前状态机实例对象 */ private final StateMachineImpl<S, E, C> stateMachine = new StateMachineImpl<>(stateMap); /** * 一对一: 外循环 * @return ExternalTransitionBuilder */ @Override public ExternalTransitionBuilder<S, E, C> externalTransition() { return new TransitionBuilderImpl<>(stateMap, TransitionType.EXTERNAL); } /** * 多起始状态对一个终态: 外循环 * @return ExternalTransitionsBuilder */ @Override public ExternalTransitionsBuilder<S, E, C> externalTransitions() { return new TransitionsBuilderImpl<>(stateMap, TransitionType.EXTERNAL); } /** * 起始状态等于最终状态:内循环 * @return */ @Override public InternalTransitionBuilder<S, E, C> internalTransition() { return new TransitionBuilderImpl<>(stateMap, TransitionType.INTERNAL); } @Override public StateMachine<S, E, C> build(String machineId) { stateMachine.setMachineId(machineId); stateMachine.setReady(true); StateMachineFactory.register(stateMachine); return stateMachine; } }
public class StateMachineFactory { /** * 状态机工厂,来储存所有的状态,key:状态机唯一标识,value状态机 */ static Map<String /* machineId */, StateMachine> stateMachineMap = new ConcurrentHashMap<>(); /** * 注册状态机 * * @param stateMachine * @param <S> * @param <E> * @param <C> */ public static <S, E, C> void register(StateMachine<S, E, C> stateMachine) { String machineId = stateMachine.getMachineId(); if (stateMachineMap.get(machineId) != null) { throw new StateMachineException("The state machine with id [" + machineId + "] is already built, no need to build again"); } stateMachineMap.put(stateMachine.getMachineId(), stateMachine); } ...... }
/** * 状态机工厂,来储存所有的状态,key:状态机唯一标识,value状态机 */ static Map<String /* machineId */, StateMachine> stateMachineMap = new ConcurrentHashMap<>();
- key:machineId是状态机唯一标识,这个标识具体表现,举一个例子。比如OFC项目,OFC项目是通过控制单据状态来达到流程控制。OFC项目中分为:出库流程,入库流程。这两个流程(也是两个不同作用域)。入库流程中包含了:创建,收货,上架等等行为。出库流程包含了:创建,分配库存,拣货下架,发货出库等等行为。这两个流程是完全不同的作用域,它们分别作用在入库单上,和出库单上。因此建议使用两个不同的状态机来做区分,即两个不同的machineId。
- value: StateMachine是一个状态机对象,这个对象可以粗浅的认为是:一个作用域(比如:入库流程)。
第二个MAP: StateMachineBuilderImpl中的stateMap
/** * StateMap is the same with stateMachine, as the core of state machine is holding reference to states. * 状态枚举持有对状态机的引用,key: 起始状态,value: State */ private final Map<S, State< S, E, C>> stateMap = new ConcurrentHashMap<>()
- key:起始状态枚举
- state:起始状态对应的状态对象
DSL语法实现:
目前提供了2种实现: TransitionBuilderImpl,TransitionsBuilderImpl
class TransitionBuilderImpl<S, E, C> implements ExternalTransitionBuilder<S, E, C>, InternalTransitionBuilder<S, E, C>, From<S, E, C>, On<S, E, C>, To<S, E, C> { /** * 状态机集合 */ final Map<S, State<S, E, C>> stateMap; /** * 源状态 */ private State<S, E, C> source; /** * 目标状态 */ protected State<S, E, C> target; /** * 状态扭转实体 */ private Transition<S, E, C> transition; /** * 状态扭转类型 */ final TransitionType transitionType; public TransitionBuilderImpl(Map<S, State<S, E, C>> stateMap, TransitionType transitionType) { this.stateMap = stateMap; this.transitionType = transitionType; } /** * 起始状态 * @param stateId id of state * @return */ @Override public From<S, E, C> from(S stateId) { source = StateHelper.getState(stateMap, stateId); return this; } /** * 目标状态 * @param stateId id of state * @return */ @Override public To<S, E, C> to(S stateId) { target = StateHelper.getState(stateMap, stateId); return this; } /** * 起始状态等于目标状态 * @param stateId id of transition * @return */ @Override public To<S, E, C> within(S stateId) { source = target = StateHelper.getState(stateMap, stateId); return this; } /** * 判断条件 * @param condition transition condition * @return */ @Override public When<S, E, C> when(Condition<C> condition) { transition.setCondition(condition); return this; } /** * 执行的事件 * @param event transition event * @return */ @Override public On<S, E, C> on(E event) { transition = source.addTransition(event, target, transitionType); return this; } /** * 需要执行的动作 * @param action performed action */ @Override public void perform(Action<S, E, C> action) { transition.setAction(action); } }
@Override public From<S, E, C> fromAmong(S... stateIds) { for(S stateId : stateIds) { sources.add(StateHelper.getState(super.stateMap, stateId)); } return this; } @Override public On<S, E, C> on(E event) { for(State source : sources) { Transition transition = source.addTransition(event, super.target, super.transitionType); transitions.add(transition); } return this; } ......
public class StateHelper { public static <S, E, C> State<S, E, C> getState(Map<S, State<S, E, C>> stateMap, S stateId){ State<S, E, C> state = stateMap.get(stateId); if (state == null) { //初始化state对象 state = new StateImpl<>(stateId); stateMap.put(stateId, state); } return state; } }
public class StateImpl<S, E, C> implements State<S, E, C> { protected final S stateId; private HashMap<E, Transition<S, E, C>> transitions = new HashMap<>(); public StateImpl(S stateId) { this.stateId = stateId; } @Override public Transition<S, E, C> addTransition(E event, State<S, E, C> target, TransitionType transitionType) { Transition<S, E, C> newTransition = new TransitionImpl<>(); newTransition.setSource(this); newTransition.setTarget(target); newTransition.setEvent(event); newTransition.setType(transitionType); Debugger.debug("Begin to add new transition: " + newTransition); verify(event, newTransition); transitions.put(event, newTransition); return newTransition; } /** * Per one source and target state, there is only one transition is allowed * * @param event * @param newTransition */ private void verify(E event, Transition<S, E, C> newTransition) { Transition existingTransition = transitions.get(event); if (existingTransition != null) { if (existingTransition.equals(newTransition)) { throw new StateMachineException(existingTransition + " already Exist, you can not add another one"); } } } ...... }
private State<S, E, C> source; private State<S, E, C> target; private E event; private Condition<C> condition; private Action<S, E, C> action; private TransitionType type = TransitionType.EXTERNAL; ...... @Override public State<S, E, C> transit(C ctx) { Debugger.debug("Do transition: " + this); this.verify(); if (condition == null || condition.isSatisfied(ctx)) { if (action != null) { action.execute(source.getId(), target.getId(), event, ctx); } return target; } Debugger.debug("Condition is not satisfied, stay at the " + source + " state "); return source; }
@Test public void testInternalNormal() { StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create(); builder.internalTransition() .within(States.STATE1) .on(Events.EVENT1) .when(checkCondition()) .perform(doAction()); StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID + "2"); States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context()); Assert.assertEquals(States.STATE1, target); }
@Test public void testExternalTransitionsNormal() { StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create(); builder.externalTransitions() .fromAmong(States.STATE1, States.STATE2, States.STATE3) .to(States.STATE4) .on(Events.EVENT1) .when(checkCondition()) .perform(doAction()); StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID + "1"); States target = stateMachine.fireEvent(States.STATE2, Events.EVENT1, new Context()); Assert.assertEquals(States.STATE4, target); }
@Test public void testExternalNormal() { StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create(); builder.externalTransition() .from(States.STATE1) .to(States.STATE2) .on(Events.EVENT1) .when(checkCondition()) .perform(doAction()); StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID); States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context()); Assert.assertEquals(States.STATE2, target); }
@Test public void testChooseExternalNormal() { StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create(); builder.chooseExternalTransitions() .from(States.STATE1) .on(Events.EVENT1) .caseThen(checkCondition(false), States.STATE2, doAction()) .caseThen(checkCondition(true), States.STATE3, doAction()) .end(States.STATE4, doAction()); StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID); States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context(1)); Assert.assertEquals(States.STATE2, target); }
自定义开发
public class ChooseTransitionBuilderImpl<S, E, C> implements ChooseExternalTransitionBuilder<S, E, C>, ChooseFrom<S, E, C>, ChooseOn<S, E, C> { /** * 状态机集合 */ final Map<S, State<S, E, C>> stateMap; /** * 源状态 */ private State<S, E, C> source; /** * 目标状态 */ protected State<S, E, C> target; /** * 状态扭转实体 */ private Transition<S, E, C> transition; /** * 状态扭转类型 */ final TransitionType transitionType; private E event; public ChooseTransitionBuilderImpl(Map<S, State<S, E, C>> stateMap, TransitionType transitionType) { this.stateMap = stateMap; this.transitionType = transitionType; } @Override public ChooseFrom<S, E, C> from(S stateId) { this.source = StateHelper.getState(stateMap, stateId); return this; } @Override public ChooseOn<S, E, C> on(E event) { this.event = event; return this; } @Override public ChooseOn<S, E, C> caseThen(Condition<C> condition, S stateId, Action<S, E, C> action) { target = StateHelper.getState(stateMap, stateId); transition = source.addTransitionByChoose(event, target, TransitionType.CHOOSE); transition.setAction(action); transition.setCondition(condition); return this; } @Override public void end(S stateId, Action<S, E, C> action) { target = StateHelper.getState(stateMap, stateId); transition = source.addTransitionByChoose(event, target, TransitionType.CHOOSE); transition.setAction(action); transition.setCondition(context -> true); } } @Override public Transition<S, E, C> addTransitionByChoose(E event, State<S, E, C> target, TransitionType transitionType) { verifyChoose(event); Transition<S, E, C> newTransition = new TransitionImpl<>(); newTransition.setSource(this); newTransition.setTarget(target); newTransition.setEvent(event); newTransition.setType(transitionType); Debugger.debug("Begin to add Choose Transition: " + newTransition); List<Transition<S, E, C>> transitions; if (chooseTransitions.containsKey(event)) { transitions = chooseTransitions.get(event); } else { transitions = new ArrayList<>(); } transitions.add(newTransition); eventHashMap.put(event,transitionType); chooseTransitions.put(event, transitions); return newTransition; }
StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create(); builder.chooseExternalTransitions() .from(States.STATE1) .on(Events.EVENT1) .caseThen(checkCondition(false), States.STATE1, doAction()) .caseThen(checkCondition(true), States.STATE3, doAction()) .end(States.STATE4, doAction());
扩展
- 状态机必须支持分布式。
- 状态机必须保证状态控制。
- 状态机必须保证线程安全。
本文仅供学习!所有权归属原作者。侵删!文章来源: 得物技术
文章评论