Jose Leon
Jose Leon

Reputation: 1651

Which state machine design to use if your target state is not the next one?

I've been reading up on State Machines since its likely I need to use for my next project. Most examples I find online show how to go from StateA to StateB. But what if your next desired state is not an adjacent state? Are there any common patterns/practices to achieve this? Ideally in Java, but I can read other programming languages just as well.

# Example States
WakeUp->Get Dressed->Get Car Keys->Get in Car->Drive to Work->Work

Current State: Get in Car

Problems to solve

# Scenario 1: Desired State == Work
Forgot car keys, so you have to return to previous state and then move forward in states again.

# Scenario 2: Desired State == Work
Have car keys, so move forward in states to get to Desired State.

It's very likely that State Machine may not solve this problem elegantly and I just need to hand-craft the logic, I don't mind, but thought I'd follow a common design pattern to help others understand it.

From the example above, I do not need to worry about 'internal' states, which is also true for the project I'm tackling; just in case that makes a difference in possible solutions.

Upvotes: 2

Views: 1455

Answers (1)

flakes
flakes

Reputation: 23624

Here is a simple way to define a state machine.

Define in an enum all the states that you want.

enum StateType {
   WAKE_UP, GET_DRESSED, GET_CAR_KEYS, GET_IN_CAR, DRIVE_TO_WORK, WORK
}

Have a statemachine which controls states, and a state interface which performs an action on the statemachine. The state then returns the next state to go to.

interface State {
    StateType next(StateMachine sm);
}

Implement this state for multiple types

class GetInCarState implements State {
    @Override
    public StateType next(StateMachine  sm) {
        if (sm.hasKeys()) {
            return StateType.DRIVE_TO_WORK;
        }
        return StateType.GET_CAR_KEYS;
    }
}

Now define the State Machine

class StateMachine {
    private Map<StateType, State> states = new HashMap<StateType, State>() {{
        put(StateType.WAKE_UP, new WakeUpState()); 
        put(StateType.GET_DRESSED, new GetDressedState()); 
        put(StateType.GET_CAR_KEYS, new GetCarKeysState()); 
        put(StateType.GET_IN_CAR, new GetInCarState()); 
        put(StateType.DRIVE_TO_WORK, new DriveToWorkState()); 
        put(StateType.WORK, new WorkState()); 
    }};

    private StateType currentState = StateType.WAKE_UP;

    private boolean hasCarKeys;

    public boolean hasKeys() {
        return hasCarKeys;
    }

    public void setHasKeys(boolean hasKeys) {
        hasCarKeys = hasKeys;
    }

    public void update() {
        currentState = states.get(currentState).next(this);
    }
}

Upvotes: 6

Related Questions