Reputation: 17
i recently asked a question on how to code my statemachine in a clean way. normally i code for PLC`s so im no expert in java. i got an helpfull answer to model the states as an enum, and encapsulate the transition logic inside the enums, like this:
public enum State {
s00_StandBy {
@Override
public State nextState() {
// if...
return ...;
}
},
s10_DetermineOperation {
@Override
public State nextState() {
// if ...
return ....;
}
},
public abstract State nextState();
}
But i am having trouble implementing this myself. First thing is why cant i use certain conditions inside the enum cases?
example:
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();
}
}
second problem im up against is, how do you code the enum encapsulated transitions to have multiple conditions to proceed to a single new state? like normally i would program the transition sort of like this:
//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;}
but to my understanding wih the encapsulated enums you can only jump from a certain state to another and every transition have to be coded seperately? so you get this for the above example:
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();
}
this gets out of hand fast when you have a lot of transitions, what am i doing wrong here?
Upvotes: 0
Views: 1007
Reputation: 2947
There could be several solutions.
Instead of only one method for doing the transition, you could have one for evvery trigger, buttons in your case.
For example:
public abstract State startButtonPressed();
public abstract State resetButtonPressed();
And implement this methods in every state.
Another way, is to encapsulate the fields you need to access in a class, for example Context
, an add it as an argument to the state transition method(s).
public abstract State nextState(Context context);
public State nextState(Context context) {
if(context.startBtn){
return s00_StandBy;
}
}
Of course, both solutions can be combined.
An example using context:
The context 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;
}
}
The enum:
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);
}
An example main method:
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);
}
}
Upvotes: 2