I try to represent finite state machine that are composed of states. The states have a list of transitions and a transition has a start state and an end state. In my application there can be several types of transitions which all inherit from the abstract class Transition.
I have those class in java :
public class Etat<T extends Transition<T>> {
private ObservableSet<T> listeTransitions;
}
public abstract class Transition<T extends Transition<T>> {
private Etat<T> etatDepart;
private Etat<T> etatArrivee;
}
I think I have a design problem because it seems weird to set my "Transition" class by itself. Is there another way to do it and get the same result? Would someone have done it differently?
Thanks for your help :)
CodePudding user response:
Here is an alternative way to approach the same problem. Please note, there weren't enough details about the different types of "Transitions", so I made some assumptions/left some things blank. Point out whatever you'd like me to change.
Also, I changed the way that Transitions were handled. Instead of being a separate object, Transitions can be found by seeing which State
objects are referenced by other State
objects.
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class State
{
public interface Transition
{
//put whatever methods/functionality/fields/etc that you like here.
}
public enum Type implements Transition
{
A,
B,
;
//If you add any methods to the interface, be sure to implement them in all values of this enum (or give a default/abstract implementation for them to use)
}
private final int id;
private final Map<State, Type> inboundTransitions = new HashMap<>();
private final Map<State, Type> outboundTransitions = new HashMap<>();
public State(int id)
{
this.id = id;
}
public int id()
{
return this.id;
}
public Map<State, Type> inboundTransitions()
{
return Collections.unmodifiableMap(this.inboundTransitions);
}
public Map<State, Type> outboundTransitions()
{
return Collections.unmodifiableMap(this.outboundTransitions);
}
public static void addTransition(State startingState, State endingState, Type transitionType)
{
startingState.outboundTransitions.put(endingState, transitionType);
endingState.inboundTransitions.put(startingState, transitionType);
}
public static void main(String[] args)
{
//now, to show how this would be used, using your image as an example.
State s0 = new State(0);
State s1 = new State(1);
State s2 = new State(2);
State s3 = new State(3);
State.addTransition(s0, s1, Type.B); // s0 ---b---> s1
State.addTransition(s0, s2, Type.A); // s0 ---a---> s2
State.addTransition(s1, s3, Type.A); // s1 ---a---> s3
State.addTransition(s2, s3, Type.A); // s2 ---a---> s3
}
}
And if you are using Java 14 or later, you can use Records to keep things short and simple.
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public record State(int id, Map<State, Type> inboundTransitions, Map<State, Type> outboundTransitions)
{
public interface Transition
{
//put whatever methods/functionality/fields/etc that you like here.
}
public enum Type implements Transition
{
A,
B,
;
//If you add any methods to the interface, be sure to implement them in all values of this enum (or give a default/abstract implementation for them to use)
}
public static void addTransition(State startingState, State endingState, Type transitionType)
{
startingState.outboundTransitions.put(endingState, transitionType);
endingState.inboundTransitions.put(startingState, transitionType);
}
public static void main(String[] args)
{
//now, to show how this would be used, using your image as an example.
State s0 = new State(0, new HashMap<>(), new HashMap<>());
State s1 = new State(1, new HashMap<>(), new HashMap<>());
State s2 = new State(2, new HashMap<>(), new HashMap<>());
State s3 = new State(3, new HashMap<>(), new HashMap<>());
State.addTransition(s0, s1, Type.B); // s0 ---b---> s1
State.addTransition(s0, s2, Type.A); // s0 ---a---> s2
State.addTransition(s1, s3, Type.A); // s1 ---a---> s3
State.addTransition(s2, s3, Type.A); // s2 ---a---> s3
}
}