原创

Java stateless4j 状态交换机的状态管理

github地址:https://github.com/stateless4j/stateless4j

简介

StateMachine直白可以翻译为状态交换机,如B的状态可以触发改变A的当前状态,下面的例子就是超级玛丽的StateMachine应用

StateMachineConfig配置相关方法

configure(TState state)

指定后续为什么状态下的配置,返回StateConfiguration类型对象。

substateOf(S superstate)

设置config的state为superstate的一个子状态;当状态为config设置的state状态时,stateMachine.isInState(superstate)也会返回true。

permit(T trigger, S destinationState)

指定trigger触发当前状态为destinationState状态。

ignore(T trigger)

忽略trigger的状态触发。

onExit()

从当前状态改变时所触发的动作,接收自定义的Action、Action1类型的lambda表达式。Action1类型传入的是Transition类型的参数

@FunctionalInterface
public interface Action {
    void doIt();
}

@FunctionalInterface
public interface Action1<T> {
    void doIt(T var1);
}

public class Transition<S, T> {
    private final S source;
    private final S destination;
    private final T trigger;
}

public StateConfiguration<S, T> onExit(final Action exitAction) {
    assert exitAction != null : "exitAction is null";

    return this.onExit(new Action1<Transition<S, T>>() {
        public void doIt(Transition<S, T> arg1) {
            exitAction.doIt();
        }
    });
}

public StateConfiguration<S, T> onExit(Action1<Transition<S, T>> exitAction) {
    assert exitAction != null : "exitAction is null";

    this.representation.addExitAction(exitAction);
    return this;
}

onEntry()

改变到当前状态时所触发的动作,接收自定义的Action、Action1、Action2类型的lambda表达式。

Action1类型传入的是Transition类型的参数。Action2类型第一个参数传入的Transition类型的参数,第二个参数为fire是传入参数,类型为Object[]

StateMachine触发的相关方法

fire()

触发状态变化,可以携带参数传入。

getState()

获取当前状态值

isInState(S state)

是否属于state状态

canFire(S state)

是否能触发状态变化(被ignore的也会返回true,为配置会返回false)。

getPermittedTriggers()

返回可以触发状态的List。

onUnhandledTrigger()

设置未配置触发状态的fire处理。接收自定义的Action、Action1、Action2类型的lambda表达式。第一个参数为要改变的状态值,第二个为触发的状态值,第三个为fire时传入参数,类型为Object[]。

示例

超级玛丽状态示例。

人物当前的状态枚举

package com.weilai.stateless4j;

/**
 * @author weilai
 * @email 352342845@qq.com
 * @date 2020/6/24 11:22 上午
 */
public enum CurrentStateEnum {

    /**
     * 存活
     */
    ALIVE,

    /**
     * 初始化时小形态
     */
    SMALL,

    /**
     * 吃到一个蘑菇时的大形态
     */
    BIG,

    /**
     * 吃到花朵,可攻击形态
     */
    SMALL_ATTACH,

    /**
     * 大、攻击形态
     */
    BIG_ATTACH,

    /**
     * 碰到妖怪死亡状态
     */
    DEAD
}

可以触发人物状态的枚举

package com.weilai.stateless4j;

/**
 * @author weilai
 * @email 352342845@qq.com
 * @date 2020/6/24 11:23 上午
 */
public enum TriggerEnum {

    /**
     * 蘑菇
     */
    MUSHROOM,

    /**
     * 花朵
     */
    FLOWER,

    /**
     * 妖怪
     */
    MONSTER,

    /**
     * 其他
     */
    OTHER,
}

通过StateMachineConfig配置触发规则,stateMachine.fire方法可以进行触发

package com.weilai.stateless4j;

import com.github.oxo42.stateless4j.StateMachine;
import com.github.oxo42.stateless4j.StateMachineConfig;

import java.util.Arrays;

/**
 * @author weilai
 * @email 352342845@qq.com
 * @date 2020/6/24 11:24 上午
 */
public class StateConvert {

    private static StateMachineConfig<CurrentStateEnum,TriggerEnum> config = new StateMachineConfig<>();

    static {
        /*
         * small状态时
         */
        config.configure(CurrentStateEnum.SMALL)
                /*
                 * 该状态是活着状态的一个子状态
                 */
                .substateOf(CurrentStateEnum.ALIVE)
                /*
                 * 当状态改变时
                 */
                .onExit(e-> System.out.println("onExit:" + e.getTrigger() + "触发" + e.getSource() + "改变为" + e.getDestination()))

                .onEntry((e, v2)-> {
                    System.out.println("onEntry:" + e.getTrigger() + "触发" + e.getSource() + "改变为" + e.getDestination());
                    System.out.println(Arrays.toString(v2));
                })
                /*
                  遇到蘑菇触发-->big状态
                 */
                .permit(TriggerEnum.MUSHROOM,CurrentStateEnum.BIG)
                /*
                 * 花朵触发,-->直接变为可攻击状态
                 */
                .permit(TriggerEnum.FLOWER,CurrentStateEnum.SMALL_ATTACH)
                /*
                 * 妖怪触发,死亡状态
                 */
                .permit(TriggerEnum.MONSTER,CurrentStateEnum.DEAD);

        /*
         * big状态
         */
        config.configure(CurrentStateEnum.BIG)
                /*
                 * 蘑菇触发,状态不变,
                 * permitReentry方法state变化相同,但具体执行过程有一些区别
                 */
                .ignore(TriggerEnum.MUSHROOM)
                .permit(TriggerEnum.FLOWER,CurrentStateEnum.BIG_ATTACH)
                .permit(TriggerEnum.MONSTER,CurrentStateEnum.SMALL);

        /*
         * 攻击状态
         */
        config.configure(CurrentStateEnum.SMALL_ATTACH)
                .ignore(TriggerEnum.FLOWER)
                .permit(TriggerEnum.MUSHROOM, CurrentStateEnum.BIG_ATTACH)
                .permit(TriggerEnum.MONSTER,CurrentStateEnum.DEAD);

        config.configure(CurrentStateEnum.BIG_ATTACH)
                .ignore(TriggerEnum.MUSHROOM)
                .ignore(TriggerEnum.FLOWER)
                .permit(TriggerEnum.MONSTER, CurrentStateEnum.SMALL);

        config.configure(CurrentStateEnum.DEAD)
                .ignore(TriggerEnum.MUSHROOM)
                .ignore(TriggerEnum.FLOWER)
                .ignore(TriggerEnum.MONSTER);
    }

    public static void main(String[] args) {
        StateMachine<CurrentStateEnum, TriggerEnum> stateMachine = new StateMachine<>(CurrentStateEnum.SMALL, StateConvert.config);
        System.out.println(stateMachine.getPermittedTriggers());
        // SMALL也属于活着状态
        System.out.println(stateMachine.isInState(CurrentStateEnum.ALIVE));
        stateMachine.fire(TriggerEnum.FLOWER);
        System.out.println("currentState-->"+ stateMachine.getState());
        stateMachine.fire(TriggerEnum.MUSHROOM);
        System.out.println("currentState-->"+ stateMachine.getState());
        stateMachine.fire(TriggerEnum.MONSTER);
        System.out.println("currentState-->"+ stateMachine.getState());
        // DEAD状态config为配置,所以为false
        System.out.println(stateMachine.canFire(TriggerEnum.OTHER));
        System.out.println("currentState-->"+ stateMachine.getState());
        // 设置未配置触发状态的fire处理
        stateMachine.onUnhandledTrigger((v1, v2 ,v3) -> System.out.print(v1.toString() + "、" + v2.toString() + "、" + Arrays.toString(v3)));
        stateMachine.fireInitialTransition();
        stateMachine.fire(TriggerEnum.OTHER);
    }
}

output:

[FLOWER, MONSTER, MUSHROOM]
true
onExit:FLOWER触发SMALL改变为SMALL_ATTACH
currentState-->SMALL_ATTACH
currentState-->BIG_ATTACH
onEntry:MONSTER触发BIG_ATTACH改变为SMALL
[]
currentState-->SMALL
false
currentState-->SMALL
SMALL、OTHER、[]
正文到此结束
本文目录