为什么某个状态在过渡到其子状态之一时就退出了?

时间:2019-09-25 12:56:20

标签: spring-statemachine

我正在尝试使用Spring Statemachine(版本2.1.3)实现具有嵌套状态(如下链接)的状态机。

Aimed state machine

在下面的代码中,我假设stateMachineDepth3对应于该机器

package de.iotiq.test.statemachine;

import org.springframework.statemachine.StateContext;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.guard.Guard;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;

public class Main {
    public static void main(String[] args) throws Exception {
        StateMachine<States, String> stateMachineDepth2;
        StateMachine<States, String> stateMachineDepth3;

        StateMachineBuilder.Builder<States, String> builder2 = StateMachineBuilder.builder();
        StateMachineBuilder.Builder<States, String> builder3 = StateMachineBuilder.builder();

        configureL2(builder2.configureStates(), null);
        configureL2(builder2.configureTransitions());

        configureL1(builder3.configureStates());
        configureL1(builder3.configureTransitions());

        stateMachineDepth2 = builder2.build();
        stateMachineDepth3 = builder3.build();

        stateMachineDepth2.addStateListener(new StateMachineListenerAdapter<States, String>() {

            @Override
            public void stateEntered(State<States, String> state) {
                System.out.println("State (D2) -> " + state.getId());
            }

            @Override
            public void stateExited(State<States, String> state) {
                System.out.println("State (D2) <- " + state.getId());
            }
        });

        stateMachineDepth3.addStateListener(new StateMachineListenerAdapter<States, String>() {

            @Override
            public void stateEntered(State<States, String> state) {
                System.out.println("State (D3) -> " + state.getId());
            }

            @Override
            public void stateExited(State<States, String> state) {
                System.out.println("State (D3) <- " + state.getId());
            }
        });

        stateMachineDepth2.start();
        stateMachineDepth3.start();
    }

    private static void configureL1(StateMachineStateConfigurer<States, String> states) throws Exception {
        states
            .withStates()
                .initial(States.S1)
                .state(States.S1)
                .state(States.S2)
        ;

        configureL2(states, States.S2);
    }

    private static void configureL2(StateMachineStateConfigurer<States, String> states, States parent) throws Exception {
        states
            .withStates()
                .parent(parent)
                .initial(States.S2a)
                .state(States.S2a)
                .state(States.S2b)
        ;

        configureL3(states);
    }

    private static void configureL3(StateMachineStateConfigurer<States, String> states) throws Exception {
        states
            .withStates()
                .parent(States.S2b)
                .initial(States.S2b1)
                .state(States.S2b1)
                .choice(States.S2b2)
                .state(States.S2b2)
                .state(States.S2b3)
                .state(States.S2b4)
                .state(States.S2b5)
        ;
    }

    private static void configureL1(StateMachineTransitionConfigurer<States, String> transitions) throws Exception {
        transitions
            .withExternal()
                .source(States.S1)
                .target(States.S2)
        ;

        configureL2(transitions);
    }

    private static void configureL2(StateMachineTransitionConfigurer<States, String> transitions) throws Exception {
        transitions
            .withExternal()
                .source(States.S2a)
                .target(States.S2b)
        ;

        configureL3(transitions);
    }

    private static void configureL3(StateMachineTransitionConfigurer<States, String> transitions) throws Exception {
        transitions
            .withExternal()
                .source(States.S2b1)
                .target(States.S2b2)
                .and()
            .withChoice()
                .source(States.S2b2)
                .first(States.S2b3, decide())
                .last(States.S2b4)
                .and()
            .withExternal()
                .source(States.S2b3)
                .target(States.S2b5)
                .and()
            .withExternal()
                .source(States.S2b4)
                .target(States.S2b5)
        ;
    }

    private static Guard<States, String> decide() {
        return new Guard<States, String>() {

            public boolean evaluate(StateContext<States, String> context) {

                System.out.println("eveluating...");

                return false;
            }
        };
    }
}

当我以stateMachineDepth3.start();开头时,得到以下输出

State (D3) -> S1
State (D3) <- S1
State (D3) -> S2
State (D3) -> S2a
State (D3) <- S2a
State (D3) -> S2b
State (D3) -> S2b1
eveluating...
State (D3) <- S2b1
State (D3) <- S2b
State (D3) -> S2b4
State (D3) <- S2b4
State (D3) -> S2b5

从输出中可以看出,当从S2b1过渡到S2b4时,它正在退出S2b,这不是事实。

对于stateMachineDepth2中深度为2的状态机,它由S2内部组成,看起来过渡是预期的。输出如下:

State (D2) -> S2a
State (D2) <- S2a
State (D2) -> S2b
State (D2) -> S2b1
eveluating...
State (D2) <- S2b1
State (D2) -> S2b4
State (D2) <- S2b4
State (D2) -> S2b5

您能看到我的状态机实现有问题吗?

1 个答案:

答案 0 :(得分:0)

不确定,但请参考文档https://docs.spring.io/spring-statemachine/docs/2.1.3.RELEASE/reference/#quick-example(“外部转换与本地转换”子节中的详细信息很少)

可能您应该使用本地转换 这是文档摘录 “在大多数情况下,外部和本地转换在功能上是等效的,除非在超级状态和子状态之间进行转换。本地转换不会导致退出和进入源状态(如果目标状态是主状态的子状态)相反,如果目标是源状态的超级状态,则局部转换不会导致退出和进入目标状态。下图显示了具有非常简单的超级状态和子状态的本地和外部转换之间的差异” >