我必须实施状态转换验证,例如:
'P' -> 'W' -> 'M' -> 'F' -> 'G'
'P' -> 'I' -> 'B' -> 'M' -> 'F' -> 'G'
其中"->"
表示“可以移动到”
简而言之,特定状态只能移至特定状态,而不能移至其他状态。如上例所示,P可以移至W或I,但不能移至其他任何状态。
注意:系统中的状态数量有限。
我已经阅读了有关策略模式的信息,但是我并不觉得这个特殊问题适合它。 在Java 8中实现此目标的最佳方法是什么?
答案 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);
}