如何在Java中将状态转换值限制为仅有效值?

时间:2018-12-05 11:44:41

标签: java algorithm design-patterns

我必须实施状态转换验证,例如:

'P' -> 'W' -> 'M' -> 'F' -> 'G'
'P' -> 'I' -> 'B' -> 'M' -> 'F' -> 'G'

其中"->"表示“可以移动到”

简而言之,特定状态只能移至特定状态,而不能移至其他状态。如上例所示,P可以移至W或I,但不能移至其他任何状态。

注意:系统中的状态数量有限。

我已经阅读了有关策略模式的信息,但是我并不觉得这个特殊问题适合它。 在Java 8中实现此目标的最佳方法是什么?

3 个答案:

答案 0 :(得分:5)

我的建议是写一个enum State来代表每个可用状态和有效转换:

enum State {
    G(Collections.emptySet()),
    F(Collections.singleton(G)),
    M(Collections.singleton(F)),
    B(Collections.singleton(M)),
    I(Collections.singleton(B)),
    W(Collections.singleton(M)),
    P(new HashSet<>(Arrays.asList(W, I)));

    private final Set<State> validTransitions;

    State(final Set<State> validTransitions) {
        this.validTransitions = validTransitions;
    }

    public State transitionTo(final State next) {
        if(!validTransitions.contains(next)) {
            throw new IllegalStateException();
        }
        return next;
    }
}

NB:

这仅允许状态转换DAG,如果您在State中引用了尚未声明的validTransitions,那么您将获得“ 非法前向引用 em>”编译器错误。

我认为这是一个优势,因为它将在编译时强制执行一组有效的状态,但是(如果您的状态是非循环)。


如果您使用的是Java 9 +

enum State {
    G(Collections.emptySet()),
    F(Set.of(G)),
    M(Set.of(F)),
    B(Set.of(M)),
    I(Set.of(B)),
    W(Set.of(M)),
    P(Set.of(W, I));

    private final Set<State> validTransitions;

    State(final Set<State> validTransitions) {
        this.validTransitions = validTransitions;
    }

    public State transitionTo(final State next) {
        if(!validTransitions.contains(next)) {
            throw new IllegalStateException();
        }
        return next;
    }
}

答案 1 :(得分:1)

有一个 state 模式,当然,您也可以考虑自己实现一个完整的状态机

您可以在代码中指定允许特定状态转换的事件。

换句话说:您不会考虑“黑名单”(P不能进入B),而是要明确声明(P可以进入W和I,句点)。

要进一步阅读,请参见here,以了解状态模式与状态机的关系。

答案 2 :(得分:1)

我有这样的要求。这就是我解决的方法。想法是维护一个枚举并仅在下一个状态有效时处理下一个状态。

 public enum State {
    P {
        @Override
        public Boolean isValid(State nextState) {
            return nextState==State.W || nextState==State.I;
        }
    },
    W {
        @Override
        public Boolean isValid(State nextState) {
            return nextState==State.M;
        }
    },
    M {
        @Override
        public Boolean isValid(State nextState) {
            return nextState==State.F;
        }
    },
    I {
        @Override
        public Boolean isValid(State nextState) {
            return nextState==State.B;
        }
    },
    B {
        @Override
        public Boolean isValid(State nextState) {
            return prevState==State.M;
        }
    },
    G {
        @Override
        public Boolean isValid(State nextState) {
            return false;
        }
    },
    F {
        @Override
        public Boolean isValid(State nextState) {
            return nextState==State.G;
        }
    };

    public abstract Boolean isValid(State nextState);
    }