Key Words: State design pattern
Topics at a glance:
- Delegating state manipulation using state objects.
- Let us turn on a bulb!
State design pattern
In this chapter we will see another behavioral pattern – the state pattern. We have all heard about Finite State Machines (FSM). FSM abstracts the behavior of the machine into identifiable unique entities called states. At any point of time, an FSM will be in a unique state and will exhibit behavior appropriate to that state. FSM can change from one state to another state upon the trigger of a specific event/condition.
In state pattern, we basically split the state and the machine. It is more correct to say that a machine is at a state rather than a machine has a state. In state pattern we make a State class as a base class and make each state the machine support into separate derived classes. Machine as said before, is always at a state in any given context. That said, a machine here, can be treated as a context class which will be at a state at any point of time. Machine will have a reference (pointer) to its unique state object that identifies/realizes its actual state, in that context. Machine will implement certain interfaces to manipulate its state for the clients. Machine will delegate the actual state manipulation to the state object. State object instance manages the state by executing the set of actions required to be performed in that state and also implements the necessary functionality to transition to another state as required.
For demonstrating an actual state pattern implementation, I am taking an example of a light bulb that can be turned on and off. Here the machine is defined by the Bulb class and it’s identifiable states are On_State class and Off_State class; State class being the abstract base class that machine will use to manipulate its state.
Let us see this in action.
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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #include <iostream> #include <string> using namespace std; class Bulb; class State { public: State(){} virtual ~State(){} virtual void on(Bulb *bulb); virtual void off(Bulb *bulb); }; class Bulb { private: State *current; public: Bulb(State *state) : current{state} {} ~Bulb(){} void set_current_state(State *state) { current = state; } void on() { current->on(this); } void off() { current->off(this); } }; void State::on(Bulb *bulb) { cout << "already in on state" << endl; return; } void State::off(Bulb *bulb) { cout << "already in off state" << endl; return; } class On_State : public State { public: On_State(){} ~On_State(){} void on(Bulb *bulb); void off(Bulb *bulb); }; class Off_State : public State { public: Off_State(){} ~Off_State(){} void on(Bulb *bulb); void off(Bulb *bulb); }; void On_State::on(Bulb *bulb) { // nothing to implement // just delegate this to base class State::on(bulb); } void On_State::off(Bulb *bulb) { // create an Off_State instance Off_State *new_state = new Off_State(); bulb->set_current_state(new_state); cout << "Bulb is switched off" << endl; delete this; } void Off_State::on(Bulb *bulb) { // create an Off_State instance On_State *new_state = new On_State(); bulb->set_current_state(new_state); cout << "Bulb is switched on" << endl; delete this; } void Off_State::off(Bulb *bulb) { // nothing to implement // just delegate this to base class State::off(bulb); return; } int main() { string choice; Bulb b1(new Off_State()); cout << "Bulb controller application" << endl; while(true) { choice.clear(); cout << "What to do next : ON, OFF, EXIT" << endl; cin >> choice; if(0 == choice.compare("ON")) { b1.on(); } else if(0 == choice.compare("OFF")) { b1.off(); } else if(0 == choice.compare("EXIT")) { cout << "Exiting bulb controller application" << endl; break; } } return 0; } |
Want to see the result?
Bulb controller application
What to do next : ON, OFF, EXIT
ON
Bulb is switched on
What to do next : ON, OFF, EXIT
OFF
Bulb is switched off
What to do next : ON, OFF, EXIT
OFF
already in off state
What to do next : ON, OFF, EXIT
ON
Bulb is switched on
What to do next : ON, OFF, EXIT
ON
already in on state
What to do next : ON, OFF, EXIT
OFF
Bulb is switched off
What to do next : ON, OFF, EXIT
EXIT
Exiting bulb controller application
Here, one thing to note is that, when the bulb is in ON state, a command to switch it on, will result in an error. Similarly, when bulb is in OFF state, you cannot turn it off again. i.e. On_State will only define the functionality to transition to OFF state, whereas Off_State defines the functionality to transition to ON state. Machine itself doesn’t need to track in which state it is currently at, in its course of execution. That said, using state pattern, we have separated the state and the machine.
Please go through the next chapter, which will improvise this Bulb controller application using bridge pattern.
Enjoyed the chapter? Let me know in the comments below. Thanks 😊