State Design Pattern
State can be defined as the condition of something variable. For example, working on an order processing application. The order can be in the following states: new, processing, cancelled, or complete. We will have to implement behaviours based on these states. Can a user edit a cancelled order, or can a completed order be cancelled ? So these behaviours have to be considered for each of the different states of the order.
State design pattern is one of 23 design patterns documented by the Gang of Four. Specifically, state design pattern addresses how an object can change its behaviour when its internal state changes and how state-specific behaviours can be defined so that new states can be added without altering the behaviour of existing states.
A Naive Approach to Managing State
The best way to begin understanding the state pattern is by understanding the challenges that it was developed to overcome. Naive approach is the common practice, that is, using multiple boolean to manage state. If there are just a couple of states, we could use the Naive approach but as the number of states increases, even though Naive approach will still work, but using it, starts to have an effect on the readability and complexity of our codes. Also when we use Naive approach, code changes made affect existing states.
State design pattern was developed to overcome two primary design challenges, how can an object change its behaviour when its internal state changes, and how state-specific behaviours can be defined in a way that states can be added without altering the behaviours of existing states.
State design pattern itself addresses the challenges of Naive Approach. It does so by encapsulating state-specific behaviours within separate state objects. The main class delegates the execution of its behaviours to one of the state objects at a given time instead of implementing state-specific behaviours itself.
There are three main components to the state design pattern
- Context : The context is a class which maintains an instance of a concrete state as its current state.
- Abstract state : The abstract state is an abstract class that defines an interface encapsulating all state-specific behaviours.
- Concrete states : A concrete state is a subclass of the abstract state that implements behaviours specific to a particular state of the context.
As described in the diagram above, we have the context, an abstract state, and any number of concrete states. The concrete states extends the abstract state implementing the interfaces defined in it. The context maintains a reference to one of the concrete states as its current state via the abstract state base class, as you will see with, state.handle() in the diagram. And that’s all there is to it.
It’s not a complicated pattern to implement, but it does force you to take a different approach to structuring your code. And you do so by identifying the states your object can be in, the conditions for transitioning between these states, and the state of your object when it’s initialised or its initial state.
By using the state design pattern, you have code that’s more modular, easier to read and maintain, less difficult to debug, and since the logic for each state is maintained in its own class, much easier to extend. New states can be added or the behaviours of existing states changed without the need to refactor the completed code of other states.
As good as state design pattern is, there are however, few drawbacks. First of all, they take some time to set up. This might not truly be a disadvantage as you get that time back and then some down the road, but it is something to consider. There are more moving parts. You completed the naive implementation in a single class, whereas the state pattern implementation of the same behaviours required more classes. This isn’t a bad thing in itself, but it has the potential of making your code more resource-intensive. All things being equal, the state design pattern is a great addition to your developer’s toolkit. So if you have objects in your apps that have easily identifiable states and the code in your method is starting to look like spaghetti, the state design pattern may be just the tool you’re looking for.