通过test用例分析COLA statemachine源码

概念:

State:状态

Event:事件,状态由事件触发,引起变化

Transition:流转,表示从一个状态到另一个状态

External Transition:外部流转,两个不同状态之间的流转

Internal Transition:内部流转,同一个状态之间的流转

Condition:条件,表示是否允许到达某个状态

Action:动作,到达某个状态之后,可以做什么

StateMachine:状态机

 

外部状态转移的test用例:

过程描述:起始状态STATE1,结束状态STATE2,当发生EVENT1时执行状态转移,当满足checkCondition()时,执行doAction,执行成功则返回状态STATE2,否则返回STATE1。

@Test
    public void testExternalNormal(){
        // 第一步:生成一个状态机builder
        StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
        // 第二步:设置一个外部状态转移类型的builder,并设置from\to\on\when\perform
        builder.externalTransition()
                .from(States.STATE1)
                .to(States.STATE2)
                .on(Events.EVENT1)
                .when(checkCondition())
                .perform(doAction());

        // 第三步:设置状态机的id和ready,并在StateMachineFactory中的stateMachineMap进行注册
        StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID);
        // 第四步:触发状态机
        States target = stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context());
        Assert.assertEquals(States.STATE2, target);
    }

1. 第一步:

  • StateMachineBuilderFactory.create()
public class StateMachineBuilderFactory {
    // 创建了一个StateMachineBuilderImpl实例对象
    public static <S, E, C> StateMachineBuilder<S, E, C> create(){
        return new StateMachineBuilderImpl<>();
    }
}

2. 第二步:

  • builder.externalTransition()
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<>();
    
...

    // 创建了一个TransitionBuilderImpl对象,并传入空的stateMap(状态表),类型为EXTERNAL
    @Override
    public ExternalTransitionBuilder<S, E, C> externalTransition() {
        return new TransitionBuilderImpl<>(stateMap, TransitionType.EXTERNAL);
    }

...

}
new TransitionBuilderImpl<>(stateMap, TransitionType.EXTERNAL)
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;

...

    final TransitionType transitionType;

    // 把状态表和状态机类型赋给本地变量
    public TransitionBuilderImpl(Map<S, State<S, E, C>> stateMap, TransitionType transitionType) {
        this.stateMap = stateMap;
        this.transitionType = transitionType;
    }

...

}
  • .from(States.STATE1)、.to(States.STATE2)
    
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;

...

    // 此时只是把from的state新增到stateMap中,返回结果赋给本地变量source
    @Override
    public From<S, E, C> from(S stateId) {
        source = StateHelper.getState(stateMap, stateId);
        return this;
    }

    // 此时只是把to的state新增到stateMap中,返回结果赋给本地变量target
    @Override
    public To<S, E, C> to(S stateId) {
        target = StateHelper.getState(stateMap, stateId);
        return this;
    }

...

}

 

StateHelper.getState
public class StateHelper {
    // 根据stateId获取state,如果不存在则插入stateMap
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 = new StateImpl<>(stateId);
            stateMap.put(stateId, state);
        }
        return state;
    }
}
  • .on(Events.EVENT1)

on条件:source包含transition,transition包含event、target、transitionType

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;

...

    @Override
    public On<S, E, C> on(E event) {
        transition = source.addTransition(event, target, transitionType);
        return this;
    }

...

}

source.addTransition(event, target, transitionType)

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<>();

    StateImpl(S stateId){
        this.stateId = stateId;
    }

    // 新增一个transition(状态转移对象)插入本地Map transitions中
    @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");
            }
        }
    }
}
  • .when(checkCondition())

设置transition的condition

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> {

    ...

    @Override
    public When<S, E, C> when(Condition<C> condition) {
        transition.setCondition(condition);
        return this;
    }
}
checkCondition()
public interface Condition<C> {

    /**
     * @param context context object
     * @return whether the context satisfied current condition
     */
    boolean isSatisfied(C context);

    default String name(){
        return this.getClass().getSimpleName();
    }
}    


private Condition<Context> checkCondition() {
    return (ctx) -> {return true;};
}

 

  • .perform(doAction())

设置transition的action

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> {

    ...

    @Override
    public void perform(Action<S, E, C> action) {
        transition.setAction(action);
    }


}
doAction()
public interface Action<S, E, C> {

    public void execute(S from, S to, E event, C context);

}    

private Action<States, Events, Context> doAction() {
        return (from, to, event, ctx)->{
            System.out.println(ctx.operator+" is operating "+ctx.entityId+" from:"+from+" to:"+to+" on:"+event);
        };
    }

第三步:

  • builder.build(MACHINE_ID)
public class StateMachineBuilderImpl<S, E, C> implements StateMachineBuilder<S, E, C> {

...

    private final StateMachineImpl<S, E, C> stateMachine = new StateMachineImpl<>(stateMap);

...

    // 设置状态机的id和ready,并在StateMachineFactory中的stateMachineMap进行注册
    @Override
    public StateMachine<S, E, C> build(String machineId) {
        stateMachine.setMachineId(machineId);
        stateMachine.setReady(true);
        StateMachineFactory.register(stateMachine);
        return stateMachine;
    }

}
public class StateMachineFactory {
    static Map<String /* machineId */, StateMachine> stateMachineMap = new ConcurrentHashMap<>();

    // 将状态机插入stateMachineMap,判断machineId是否重复
    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);
    }
}

第四步:

  • stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context())
public class StateMachineImpl<S,E,C> implements StateMachine<S, E, C> {

    private String machineId;

    private final Map<S, State<S,E,C>> stateMap;

    private boolean ready;

    public StateMachineImpl(Map<S, State< S, E, C>> stateMap){
        this.stateMap = stateMap;
    }

    // 触发状态机
    public S fireEvent(S sourceStateId, E event, C ctx){
        isReady();
        State sourceState = getState(sourceStateId);
        return doTransition(sourceState, event, ctx).getId();
    }

    // 执行转移
    private State<S, E, C> doTransition(State sourceState, E event, C ctx) {
        Optional<Transition<S,E,C>> transition = sourceState.getTransition(event);
        if(transition.isPresent()){
            return transition.get().transit(ctx);
        }
        Debugger.debug("There is no Transition for " + event);
        return sourceState;
    }

    // 根据stateId获取状态机当前state
    private State getState(S currentStateId) {
        State state = StateHelper.getState(stateMap, currentStateId);
        if(state == null){
            showStateMachine();
            throw new StateMachineException(currentStateId + " is not found, please check state machine");
        }
        return state;
    }

    // 判断状态机是否准备完毕
    private void isReady() {
        if(!ready){
            throw new StateMachineException("State machine is not built yet, can not work");
        }
    }

...

}

sourceState.getTransition(event)

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<>();

...

    // 根据event获取transition(转移对象)
    @Override
    public Optional<Transition<S, E, C>> getTransition(E event) {
        return Optional.ofNullable(transitions.get(event));
    }

...

}

transition.get().transit(ctx)

test用例中作者对于Condition和Action的实现类简单处理了,实际使用时应该分别实现这两个接口中的方法。

public class TransitionImpl<S,E,C> implements Transition<S,E,C> {

    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;

    ...

    // 执行转移,如果满足condition,则执行action,并返回状态targe,否则返回状态source
    @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;
    }

    // 如果是内部转移类型,source必须等于target
    @Override
    public void verify() {
        if(type== TransitionType.INTERNAL && source != target) {
            throw new StateMachineException(String.format("Internal transition source state '%s' " +
                    "and target state '%s' must be same.", source, target));
        }
    }
}

 

多个外部状态转移的test用例:

和单个的起始状态的差别不大,只是builder在维护source和transition是map

@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用例:

外部状态转移唯一的差别在于from和to的state是同一个。

@Test
    public void testInternalNormal(){
        StateMachineBuilder<States, Events, Context> builder = StateMachineBuilderFactory.create();
        builder.internalTransition()
                .within(States.STATE1)
                .on(Events.INTERNAL_EVENT)
                .when(checkCondition())
                .perform(doAction());
        StateMachine<States, Events, Context> stateMachine = builder.build(MACHINE_ID+"2");

        stateMachine.fireEvent(States.STATE1, Events.EVENT1, new Context());
        States target = stateMachine.fireEvent(States.STATE1, Events.INTERNAL_EVENT, new Context());
        Assert.assertEquals(States.STATE1, target);
    }

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值