I figured out this way of modelling a finite state automaton in Java.
The more pruning unnecessary or redundant classes, the more I found that the State pattern wasn't required at all. Instead, a proper Strategy pattern seems to do the job quite nicely.
The following classes represent the FSA of a Gate (state digram below):
/**
*
* @author Anton Maria Prati
*/
public class GateFSA {
GateStateBehaviour stateBehaviour = new ShutGateStateBehaviour();
String getState(){
return stateBehaviour.getState();
}
void honk(){
transition(GateEvent.HONK);
}
void stay(){
transition(GateEvent.STAY);
}
void alarm(){
transition(GateEvent.ALARM);
}
void transition(GateEvent event){
System.out.print(getState());
System.out.print(" -" + event + "-> ");
stateBehaviour = stateBehaviour.transition(event);
System.out.println(getState());
}
}
interface GateStateBehaviour{
public GateStateBehaviour transition(GateEvent event);
public String getState();
}
class ShutGateStateBehaviour implements GateStateBehaviour {
@Override
public GateStateBehaviour transition(GateEvent event) {
GateStateBehaviour nextBehaviour = this;
if (event == GateEvent.HONK)
nextBehaviour = new RisingGateStateBehaviour();
if (event == GateEvent.ALARM)
nextBehaviour = new OpenGateStateBehaviour();
return nextBehaviour;
}
@Override
public String getState() {
return "SHUT";
}
}
class OpenGateStateBehaviour implements GateStateBehaviour {
@Override
public GateStateBehaviour transition(GateEvent event) {
GateStateBehaviour nextBehaviour = this;
if (event == GateEvent.HONK || event == GateEvent.STAY)
nextBehaviour = new DescendingGateStateBehaviour();
else if (event == GateEvent.ALARM)
nextBehaviour = new ShutGateStateBehaviour();
return nextBehaviour;
}
@Override
public String getState() {
return "OPEN";
}
}
class DescendingGateStateBehaviour implements GateStateBehaviour {
@Override
public GateStateBehaviour transition(GateEvent event) {
GateStateBehaviour nextBehaviour = this;
if (event == GateEvent.HONK)
nextBehaviour = new RisingGateStateBehaviour();
else if (event == GateEvent.STAY)
nextBehaviour = new ShutGateStateBehaviour();
return nextBehaviour;
}
@Override
public String getState() {
return "DESCENDING";
}
}
class RisingGateStateBehaviour implements GateStateBehaviour {
@Override
public GateStateBehaviour transition(GateEvent event) {
GateStateBehaviour nextBehaviour = this;
if (event == GateEvent.HONK)
nextBehaviour = new DescendingGateStateBehaviour();
else if (event == GateEvent.STAY)
nextBehaviour = new OpenGateStateBehaviour();
return nextBehaviour;
}
@Override
public String getState() {
return "RISING";
}
}
enum GateEvent {
HONK,
STAY,
ALARM;
}
Main() method:
GateFSA gate = new GateFSA();
gate.transition(GateEvent.HONK);
gate.transition(GateEvent.HONK);
gate.transition(GateEvent.STAY);
gate.transition(GateEvent.HONK);
gate.transition(GateEvent.STAY);
gate.transition(GateEvent.ALARM);
gate.transition(GateEvent.STAY);
Output:
I cannot seem to prefer a State Pattern over the design above. Any criticism would be greatly appreciated.
Aucun commentaire:
Enregistrer un commentaire