The State design pattern
💡Intent
The State design pattern allows an object to alter its behavior when its internal state changes at runtime.
In the State pattern, an object's behavior is determined by its current state. The object can have one of a finite number of states, and it transitions from one state to another by executing methods defined for each state. These methods are called "state transitions."
🤔 The problem and use cases
Consider a simple light switch that can be in either the "on" or "off" state. The behavior of the light switch when the switch is flipped will depend on its current state. If the light switch is currently in the "off" state, flipping the switch will turn the light on. If the light switch is currently in the "on" state, flipping the switch will turn the light off.
Similarly consider a paint or Photoshop like software. That has a canvas object, where the behavior of the tool changes when the state changes from freehand drawing to creating objects, or adding/filling colors or erasing objects.
Other examples of problems where State design pattern is suitable:
- ATM changing behavior as the state change from "welcome" to "login" to "transaction"
- Online shopping carts changing behavior as the state changes from "empty" to "non-empty" to "order placed"
- Network routers changing behavior as the state changes from "normal" to "congested" or "failure"
🌟The solution and example implementation
The State design pattern is proper when an object's behavior depends on its internal state, and when it is necessary to change the behavior of the thing at run-time based on that state.
Let's talk about the first example of light switch. The state design pattern can be used to implement the light switch in a way that makes it easy to add new states and state transitions.
We will create objects as following
The light switch could be implemented as a Context
class, with separate State
classes for the "on" and "off" states. The Context
class would maintain a reference to the current State
object, and the State
objects would define the behavior of the light switch when the switch is flipped.
This approach makes it easy to add new states to the light switch, such as a "dim" state or a "bright" state, without having to modify the Context
class. It also makes it easy to understand and maintain the light switch, since the state transitions are clearly defined and separated from the rest of the object's behavior.
In this class diagram, the Context
class maintains a reference to a State
object, which represents the current state of the context. The Context
class also has a setState()
and getState()
method for setting and getting the current state, and a handle()
method that delegates the handling of the current state to the State
object.
The State
interface defines the interface for handling state transitions, and the ConcreteStateA
and ConcreteStateB
classes are concrete implementations of the State
interface that represents different states of the context. Each of these classes has a handle()
method that defines the behavior of the context when the handle()
method is called on the Context
object.
This allows the Context
object to alter its behavior based on its current state, without the client code having to be aware of the specific details of the different states.
💻Code:
Here's an example in Java:
public interface State {
void handle();
}
public class ConcreteStateA implements State {
public void handle() {
System.out.println("This is in State A");
}
}
public class ConcreteStateB implements State {
public void handle() {
System.out.println("This is in State B");
}
}
public class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void handle() {
state.handle();
}
}
public class Main {
public static void main(String[] args) {
Context context = new Context();
context.setState(new StateA());
context.handle(); // Output: "This is in State A"
context.setState(new StateB());
context.handle(); // Output: "This is in State B"
}
}
In this example, the Context
class maintains a reference to a State
object, which represents the current state of the context. The Context
class also has a handle()
method that delegates the handling of the current state to the State
object.
The State
interface defines the interface for handling state transitions. The ConcreteStateA
and ConcreteStateB
classes are concrete implementations of the State
interface that represents different states of the context.
When the handle()
method is called on the Context
object, it delegates the call to the handle()
method of the current State
object. This allows the Context
object to alter its behavior based on its current state, without the client code having to be aware of the specific details of the different states.
In general, the state design pattern is useful for any situation where the behavior of an object depends on its internal state and that behavior needs to be changed at run-time based on that state.
Pros and Cons
Pros ✅
- It allows an object to alter its behavior when its internal state changes, without the client code having to be aware of the specific details of the different states.
- It can reduce the complexity of an object by separating its behavior into distinct states, rather than having all of the behavior defined in a single class.
- It can make it easier to add new states to an object since the state transitions are handled by the state classes rather than the object itself.
- It can make it easier to maintain and debug an object since the state transitions are clearly defined and separated from the rest of the object's behavior.
Cons ❌
- It can make the code more complex since it requires the creation of multiple state classes and the implementation of state transitions.
- It can make the code more difficult to understand since the object's behavior is determined by its current state and the state transitions are not always obvious.
- It can make the object more difficult to test since its behavior depends on its current state and the state transitions.
Learning faster with Developer Diary
If you want to further improve your productivity, try out Developer Diary. Developer Diary brings clarity and insights to reach the Flow state faster. When you are working on your coding problem and remember to note something down or ask ChatGPT something, you can use a simple shortcut (`⌘+Shift+I`) to open the app and start journaling.
If you want to read more such article, do subscribe to our newsletter. Where we share the articles on technology, 100% remote developer jobs 🌎, developer productivity hacks, and insights from the Invide Remote Developers Community.
To discuss it with other fellow developers, join our Discord Server.
Member discussion