State Pattern
Contents
The same input can produce a different output, depending on the context/current state of the machine .
+Pressing "Coke" on a Vending Machine won'give a Coke un*ess it has money inside.flowchartDiagrams: enable: false * options: ""
sequenceDiagrams: enable: false options: ""
State Machine
A finite state machine has, at any given time, only one state.
The state changes only in response to some external input.
The change from one state to another is called a transition
The same input can produce a different output, depending on the context/current state of the machine.
i.e. Pressing "Coke" on a Vending Machine won't give a Coke unless it has money inside.
A basic state pattern
Consider the three inputs X
, Y
, Z
, and the three states A
, B
, C
1 2 3 4 5 6 7 8 9 10 11 12 | myY() { if (currentState == A) { ... currentState = B; } else if (currentState == B) { ... currentState = C; } else if (currentState == C) { ... currentState = A; } } |
The same state pattern, with switch
1 2 3 4 5 6 7 8 9 10 11 12 | myY() { switch (currentState) { case A: ... currentState = B; case B: ... currentState = C; case C: ... currentState = A; } |
Issues
This is bad! Each new input or state will require the modification of all relevant if
/else if
/ switch
statements.
Solution
Instead, for each given state we could create a class that implements a common interface.
|
|
Setting the state
In order to update the next state, we will have to pass in a way for the state to change.
Ideas
- Pass
this
into all methods - Pass
this
(context) in the state constructor- Create a
setContext
method in the context, which the states can call
- Create a
- Pass an update callback function
this.state.myFunction(this.changeState);
- The return type of the values could be the next state
this.state = this.state.myFunction();
Best Method: Pass the context into the state class through the constructor. It is also a good idea to create the states during the initialisation of the context