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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
interface ObjState {
  void myX();
  void myY();
  void myZ();
}

class stateA implements ObjState {
  void myX() {
    ...
  }

  void myY() {
    ...
  }

  void myZ() {
    ...
  }
}

class stateB implements ObjState {
  void myX() {
    ...
  }

  void myY() {
    ...
  }

  void myZ() {
    ...
  }
}

class stateC implements ObjState {
  void myX() {
    ...
  }

  void myY() {
    ...
  }

  void myZ() {
    ...
  }
}

class MyClassWithState implements ObjState {
  private ObjState state;

  MyClassWithState() {
    this.state = new stateA();
  }

  void myX() {
    this.state.myX();
  }

  void myY() {
    this.state.myY();
  }

  void myZ() {
    this.state.myZ();
  }
}

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
  • 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