Design pattern "State"

Let's learn what is the "State" design pattern πŸƒπŸ»β€β™‚οΈπŸšΆπŸ»πŸ›ŒπŸ»
Friday, July 5, 2024

Real world example

The β€œstate” design patterns works like a state machine (also known as a finite state machine). A state machine is defined by a list of its states, its initial state, and the conditions for each transition to go from one state to another. However, it’s important to note that the machine can only be in one of these states at any particular moment. It changes from one state to another in response to some external inputs.

Finite state machines are widely used in modeling of application behavior, design of hardware digital systems, software engineering, compilers, network protocols, and the study of computation and languages.


Let’s consider a real-world example of the state design pattern: an Order processing system. In this system, an order can be in various states such as NewState, ProcessedState, ShippedState, DeliveredState, and CancelledState.

We can draw our states like this:

Loading graph...

Using this pattern avoids using switch/case or if/else structure which can be a little tedious and hard to maintain.

// ❌ Example of bad code
if (state instanceof NewState) {
// ...
} else if (state instanceof ProcessedState) {
// ...
} else if (state instanceof ShippedState) {
// ...
} else if (state instanceof DeliveredState) {
// ...
} else if (state instanceof CancelledState) {
// ...
}

In plain words

It lets you change the behavior of a class when the state changes.

Wikipedia definition

The state pattern is a behavioral software design pattern that implements a state machine in an object-oriented way. With the state pattern, a state machine is implemented by implementing each individual state as a derived class of the state pattern interface, and implementing state transitions by invoking methods defined by the pattern’s superclass. The state pattern can be interpreted as a strategy pattern which is able to switch the current strategy through invocations of methods defined in the pattern’s interface.

Programmatic example

First, let’s create all our states:

abstract class State {
protected Order order;
public State(Order order) {
this.order = order;
}
public abstract void nextState();
public abstract void prevState();
public abstract void printState();
}
class NewState extends State {
public NewState(Order order) {
super(order);
}
@Override
public void nextState() {
order.setState(new ProcessedState(order));
}
@Override
public void prevState() {
// No previous state for NewState
}
@Override
public void printState() {
System.out.println("Order status: New");
}
}
class ProcessedState extends State {
public ProcessedState(Order order) {
super(order);
}
@Override
public void nextState() {
order.setState(new ShippedState(order));
}
@Override
public void prevState() {
order.setState(new NewState(order));
}
@Override
public void printState() {
System.out.println("Order status: Processed");
}
}
// Other state classes (ShippedState, DeliveredState, CancelledState) follow a similar pattern

Then, let’s create our Order class:

class Order {
private State state;
public Order() {
this.state = new NewState(this); // Default state
}
public void setState(State state) {
this.state = state;
}
// Write down here the list of actions you want to be able to perform
public void nextState() {
state.nextState();
}
public void prevState() {
state.prevState();
}
public void printState() {
state.printState();
}
}

Let’s play with our code:

public class Main {
public static void main(String[] args) {
Order order = new Order();
order.printState(); // New
order.nextState();
order.printState(); // Processed
order.nextState();
order.printState(); // Shipped
order.prevState();
order.printState(); // Processed
// ...
}
}

Diagram

Loading graph...

Some other examples

  1. Media Players: Media players often have different states like playing, paused, stopped, etc. The behavior of the player changes based on its state.
  2. Traffic Lights: A traffic light system can be modeled using the state pattern with states like red, yellow, and green, each having different behaviors.
  3. Authentication Systems: In an authentication system, a user can be in various states like authenticated, unauthenticated, or in the process of authentication.
  4. Game Development: In game development, a game character could have states like idle, running, jumping, etc. The character’s behavior changes based on its current state.
  5. Document Management Systems: A document in a workflow might have states like draft, review, approved, published, etc. The operations that can be performed on the document depend on its state.
  6. E-commerce Systems: An order in an e-commerce system can have states like new, paid, shipped, delivered, etc. The transitions between these states can be managed using the state pattern.
  7. Networking: Network connections can have different states like established, listen, closed, etc. The behavior of the connection changes based on its state.
  8. Operating Systems: An operating system manages processes which can be in states like start, ready, running, waiting, etc.
  9. UI Development: In UI development, a component could have states like enabled, disabled, hover, active, etc. The appearance and behavior of the component change based on its state.
  10. Printers: A printer can have states like idle, printing, out of paper, out of ink, etc. The operations that can be performed on the printer depend on its state.

Recommended articles