I have multiple entities in my application like Users, Accounts, Licenses etc. Each entity has a status associated with it like Active, Ok, Suspended, Unverified, PendingPayment, PendingApproval etc. I want to make sure the entities can move from a predefined status to another like User can only move from Ok to Suspended but not from Unverified to Suspended. What would be the best design pattern to implement this ? I have looked around and mostly find state machines for such problems, but they look too complex for this as I don't want to consider events in the state. All I want to restrict is the transition of states.
As of now, I can think of using a pre-populated 2D array that defines all statuses in each dimension and represents possible transitions. Looking for any better approaches.
You can use in JPA enumerated type. Have a look in the link below. http://tomee.apache.org/examples-trunk/jpa-enumerated/README.html
public enum State {
STATE1,STATE2(STATE1),STATE3(STATE1,STATE2);
private State[] previousStates;
private State(){
}
private State(State ...state) {
this.previousStates =state;
}
public State transition(State state) throws Exception {
for(State tmp: state.previousStates) {
if (this == tmp) {
return state;
}
}
throw new Exception("Illegal state");
}
}
By implementing the method transition within the Enum you will be able to easily set new values for the enum in the JPA you can hide this invocation right into your set method and also it will just throw Exception if the status is incorrect.
Alexander's proposal is fine as long as:
For the first bullet point, you might want to consider to implement states as Objects not as enums. Each object/state could have a method that tells you if it was ok to switch to it depending on the current state.
interface State {
boolean isSwitchOk(State currentState);
}
class FinishedState implements State {
boolean isSwitchOk(State currentState) {
...
}
}
You could do it the other way round, as well, i.e. nextState instead of previousState.
In case you need states that can be added at runtime, you could persist them in the DB of your choice. For instance, map the following to your DB (as a JPA example)
@Entity
public class State {
@OneToMany
private List<State> permittedNextStates;
public isSwitchOk(State nextState) {
return permittedNextStates.contains(nextState);
}
}
}
In your entity, you could then do
public class MyEntity {
private State currentState;
public void switchTo(State nextState) {
if (currentState.isSwitchOk(nextState)) {
this.currentState = state;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With