The State design pattern is a behavioral pattern that allows an object to change its behavior when its internal state changes. This pattern is useful when we have an object that can be in different states and each state has different behavior. In this article, we will discuss the State design pattern in Java and how it can be used to solve real-world problems.
Overview of State Design Pattern
The State design pattern is used when an object needs to change its behavior based on its internal state. The pattern is composed of three main elements:
Context – The context represents the object that can change its behavior based on its internal state. The context maintains a reference to the current state object and delegates its behavior to that object.
State – The state represents the different states that the context object can be in. Each state object defines its own behavior.
Transition – The transition represents the mechanism that changes the state of the context object. The transition can be initiated by the context object or by a client of the context object.
Example Use Case of State Design Pattern in Java
Let’s say we have a vending machine that dispenses different items based on its state. The machine can be in three states:
NoSelectionState – when no item has been selected yet
ItemSelectedState – when an item has been selected but not dispensed yet
ItemDispensedState – when an item has been dispensed
First, we will create an interface for our states:
public interface VendingMachineState {
void selectItem();
void dispenseItem();
}
Next, we will create the three concrete state classes:
public class NoSelectionState implements VendingMachineState {
@Override
public void selectItem() {
System.out.println("Item selected");
}
@Override
public void dispenseItem() {
System.out.println("Please select an item first");
}
}
public class ItemSelectedState implements VendingMachineState {
@Override
public void selectItem() {
System.out.println("Item already selected");
}
@Override
public void dispenseItem() {
System.out.println("Item dispensed");
}
}
public class ItemDispensedState implements VendingMachineState {
@Override
public void selectItem() {
System.out.println("Vending machine empty");
}
@Override
public void dispenseItem() {
System.out.println("Vending machine empty");
}
}
Finally, we will create our context class, which will hold the current state and allow us to transition between states:
public class VendingMachine {
private VendingMachineState currentState;
public VendingMachine() {
currentState = new NoSelectionState();
}
public void setState(VendingMachineState state) {
currentState = state;
}
public void selectItem() {
currentState.selectItem();
if (currentState instanceof NoSelectionState) {
setState(new ItemSelectedState());
}
}
public void dispenseItem() {
currentState.dispenseItem();
if (currentState instanceof ItemSelectedState) {
setState(new ItemDispensedState());
}
}
}
Here, the VendingMachine class holds the current state in the currentState variable. The setState method is used to transition between states. The selectItem and dispenseItem methods are called to trigger the corresponding actions in the current state.
Now, we can use our VendingMachine class as follows:
VendingMachine vendingMachine = new VendingMachine();
vendingMachine.selectItem(); // Output: Item selected
vendingMachine.dispenseItem(); // Output: Please select an item first
vendingMachine.selectItem(); // Output: Item already selected
vendingMachine.dispenseItem(); // Output: Item dispensed
vendingMachine.selectItem(); // Output: Vending machine empty
vendingMachine.dispenseItem(); // Output: Vending machine empty
This is just a simple example, but the State Design Pattern can be useful for managing complex state transitions in a variety of contexts.
Pingback: GoF (Gang of Four) Design Pattern - Java To The Point