如何使用提供的示例在状态机中的状态之间进行适当的转换
how to do proper transitions between states in statemachine with provided example
我最近问了一个关于如何以干净的方式编写状态机代码的问题。通常我为 PLC 编写代码,所以我不是 java 方面的专家。
我得到了一个有用的答案,将状态建模为枚举,并将转换逻辑封装在枚举中,如下所示:
public enum State {
s00_StandBy {
@Override
public State nextState() {
// if...
return ...;
}
},
s10_DetermineOperation {
@Override
public State nextState() {
// if ...
return ....;
}
},
public abstract State nextState();
}
但我自己实施时遇到了问题。
首先是为什么我不能在枚举案例中使用某些条件?
示例:
boolean resetBtn,startBtn;
State currentState;
//Transition logic
public enum State {
//if state is s00_standBy and startBtn is true proceed to s10
s00_StandBy {
@Override
public State nextState() {
if(startBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s10_DetermineOperation;
}
}
};
public abstract State nextState();
}
//Main
public void main() throws Exception {
//while in this state do stuff
if(currentState.equals(State.s00_StandBy)) {
//when done or condition is met go to next state
currentState.nextState();
}
}
我遇到的第二个问题是,如何编写枚举封装的转换代码,使其具有多个条件以继续进入单个新状态?
像往常一样,我会像这样对过渡进行编程:
//state
if (currentState.equals(s10_DetermineOperation) && resetBtn = true)
Or (currentState.equals(s20_normalOperation) && resetBtn=true)
Or (currentState.equals(s30_someOtherState) && resetBtn=true){
return state.s00_StandBy;}
但是根据我的理解,封装的枚举只能从某个状态跳到另一个状态,并且每个转换都必须单独编码?
所以你在上面的例子中得到了这个:
boolean resetBtn,startBtn;
State currentState;
//Transition logic
public enum State {
//if state is s00_standBy and startBtn is true proceed to s10
s10_DetermineOperation {
@Override
public State nextState() {
if(startBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
s20_normalOperation {
@Override
public State nextState() {
if(resetBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
s30_normalOperation {
@Override
public State nextState() {
if(resetBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
public abstract State nextState();
}
当你有很多转换时,这很快就会失控,我在这里做错了什么?
可能有多种解决方案。
在您的情况下,您可以为每个触发器、按钮使用一种方法,而不是只有一种方法来进行转换。
例如:
public abstract State startButtonPressed();
public abstract State resetButtonPressed();
并在每个州实施此方法。
另一种方法是将您需要访问的字段封装在 class 中,例如 Context
,并将其作为参数添加到状态转换方法中。
public abstract State nextState(Context context);
public State nextState(Context context) {
if(context.startBtn){
return s00_StandBy;
}
}
当然,这两种解决方案可以结合使用。
编辑
使用上下文的示例:
上下文 class:
public class Context {
private boolean bool1;
private boolean bool2;
public Context() {
}
public boolean isBool1() {
return bool1;
}
public void setBool1(boolean bool1) {
this.bool1 = bool1;
}
public boolean isBool2() {
return bool2;
}
public void setBool2(boolean bool2) {
this.bool2 = bool2;
}
}
枚举:
public enum State {
s00_StandBy {
@Override
public State nextState(Context context) {
if (context.isBool1()) {
return s99_otherState;
} else {
return s20_someOtherState;
}
}
},
s20_someOtherState {
@Override
public State nextState(Context context) {
if (context.isBool2()) {
return s99_otherState;
} else {
return s00_StandBy;
}
}
},
s99_otherState {
@Override
public State nextState(Context context) {
return s00_StandBy;
}
};
public abstract State nextState(Context context);
}
主要方法示例:
public class Main {
public static void main(String... args) {
Context context = new Context();
State currentState = State.s00_StandBy;
context.setBool1(true);
currentState = currentState.nextState(context);
System.out.println(currentState);
}
}
我最近问了一个关于如何以干净的方式编写状态机代码的问题。通常我为 PLC 编写代码,所以我不是 java 方面的专家。 我得到了一个有用的答案,将状态建模为枚举,并将转换逻辑封装在枚举中,如下所示:
public enum State {
s00_StandBy {
@Override
public State nextState() {
// if...
return ...;
}
},
s10_DetermineOperation {
@Override
public State nextState() {
// if ...
return ....;
}
},
public abstract State nextState();
}
但我自己实施时遇到了问题。 首先是为什么我不能在枚举案例中使用某些条件?
示例:
boolean resetBtn,startBtn;
State currentState;
//Transition logic
public enum State {
//if state is s00_standBy and startBtn is true proceed to s10
s00_StandBy {
@Override
public State nextState() {
if(startBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s10_DetermineOperation;
}
}
};
public abstract State nextState();
}
//Main
public void main() throws Exception {
//while in this state do stuff
if(currentState.equals(State.s00_StandBy)) {
//when done or condition is met go to next state
currentState.nextState();
}
}
我遇到的第二个问题是,如何编写枚举封装的转换代码,使其具有多个条件以继续进入单个新状态? 像往常一样,我会像这样对过渡进行编程:
//state
if (currentState.equals(s10_DetermineOperation) && resetBtn = true)
Or (currentState.equals(s20_normalOperation) && resetBtn=true)
Or (currentState.equals(s30_someOtherState) && resetBtn=true){
return state.s00_StandBy;}
但是根据我的理解,封装的枚举只能从某个状态跳到另一个状态,并且每个转换都必须单独编码? 所以你在上面的例子中得到了这个:
boolean resetBtn,startBtn;
State currentState;
//Transition logic
public enum State {
//if state is s00_standBy and startBtn is true proceed to s10
s10_DetermineOperation {
@Override
public State nextState() {
if(startBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
s20_normalOperation {
@Override
public State nextState() {
if(resetBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
s30_normalOperation {
@Override
public State nextState() {
if(resetBtn){ // Cant use startBtn here? how to use conditions from outside the enum case?
return s00_StandBy;
}
}
},
public abstract State nextState();
}
当你有很多转换时,这很快就会失控,我在这里做错了什么?
可能有多种解决方案。
在您的情况下,您可以为每个触发器、按钮使用一种方法,而不是只有一种方法来进行转换。
例如:
public abstract State startButtonPressed();
public abstract State resetButtonPressed();
并在每个州实施此方法。
另一种方法是将您需要访问的字段封装在 class 中,例如 Context
,并将其作为参数添加到状态转换方法中。
public abstract State nextState(Context context);
public State nextState(Context context) {
if(context.startBtn){
return s00_StandBy;
}
}
当然,这两种解决方案可以结合使用。
编辑
使用上下文的示例:
上下文 class:
public class Context {
private boolean bool1;
private boolean bool2;
public Context() {
}
public boolean isBool1() {
return bool1;
}
public void setBool1(boolean bool1) {
this.bool1 = bool1;
}
public boolean isBool2() {
return bool2;
}
public void setBool2(boolean bool2) {
this.bool2 = bool2;
}
}
枚举:
public enum State {
s00_StandBy {
@Override
public State nextState(Context context) {
if (context.isBool1()) {
return s99_otherState;
} else {
return s20_someOtherState;
}
}
},
s20_someOtherState {
@Override
public State nextState(Context context) {
if (context.isBool2()) {
return s99_otherState;
} else {
return s00_StandBy;
}
}
},
s99_otherState {
@Override
public State nextState(Context context) {
return s00_StandBy;
}
};
public abstract State nextState(Context context);
}
主要方法示例:
public class Main {
public static void main(String... args) {
Context context = new Context();
State currentState = State.s00_StandBy;
context.setBool1(true);
currentState = currentState.nextState(context);
System.out.println(currentState);
}
}