Allow an object to alter its behavior when its internal state changes โ making the object appear to change its class.
๐ง What Is the State Pattern?
The State Pattern is a behavioral design pattern that:
- Encapsulates state-specific behavior into separate classes.
- Delegates state transitions and behavior to these state objects.
- Avoids conditionals (
if-else,switch-case) spread across methods.
โ Real-World Use Cases
| System/Domain | Example of States |
|---|---|
| ๐ซ Movie Booking | SeatAvailable โ Reserved โ Paid โ Cancelled |
| ๐ง ATM Machine |
CardInserted, PinVerified, CashDispensed
|
| ๐ฆ Traffic Signal | Red โ Yellow โ Green |
| ๐ถ Network Connection |
Connected, Disconnected, Reconnecting
|
| ๐ Document Workflow |
Draft, Reviewed, Approved, Published
|
๐ When to Use It?
โ Use State Pattern when:
- An object must behave differently depending on internal state.
- You have lots of conditional logic (
if/switch) that varies by state. - State transitions are part of business logic.
๐งฑ Pattern Structure (LLD)
| Component | Responsibility |
|---|---|
| State (interface) | Declares operations per state |
| ConcreteState | Implements behavior for a specific state |
| Context | Maintains current state and delegates behavior |
๐ UML Diagram
+---------------------+
| Context |
+---------------------+
| - state: State |
| +setState(State) |
| +handle() |
+---------------------+
โฒ
|
+---------------------+ +------------------------+
| State |<------+ ConcreteStateX |
+---------------------+ +------------------------+
| +handle(Context) | | +handle(Context) |
+---------------------+ +------------------------+
๐ป Java Implementation โ Vending Machine Example
Weโll model a vending machine with 3 states:
-
IdleState: Waiting for coin -
HasCoinState: Coin inserted, ready to select item -
DispensingState: Dispensing item
โ
VendingState.java
public interface VendingState {
void insertCoin(VendingMachine context);
void selectItem(VendingMachine context);
void dispense(VendingMachine context);
}
โ
IdleState.java
public class IdleState implements VendingState {
@Override
public void insertCoin(VendingMachine context) {
System.out.println("๐ช Coin inserted. Ready to select item.");
context.setState(new HasCoinState());
}
@Override
public void selectItem(VendingMachine context) {
System.out.println("โ Insert coin first.");
}
@Override
public void dispense(VendingMachine context) {
System.out.println("โ Cannot dispense. No item selected.");
}
}
โ
HasCoinState.java
public class HasCoinState implements VendingState {
@Override
public void insertCoin(VendingMachine context) {
System.out.println("โ Coin already inserted.");
}
@Override
public void selectItem(VendingMachine context) {
System.out.println("๐ฆ Item selected. Dispensing now...");
context.setState(new DispensingState());
}
@Override
public void dispense(VendingMachine context) {
System.out.println("โ Select an item first.");
}
}
โ
DispensingState.java
public class DispensingState implements VendingState {
@Override
public void insertCoin(VendingMachine context) {
System.out.println("โ Please wait. Dispensing in progress.");
}
@Override
public void selectItem(VendingMachine context) {
System.out.println("โ Already dispensing.");
}
@Override
public void dispense(VendingMachine context) {
System.out.println("โ
Item dispensed. Back to idle.");
context.setState(new IdleState());
}
}
โ
VendingMachine.java (Context)
public class VendingMachine {
private VendingState currentState;
public VendingMachine() {
this.currentState = new IdleState(); // Initial state
}
public void setState(VendingState state) {
this.currentState = state;
}
public void insertCoin() {
currentState.insertCoin(this);
}
public void selectItem() {
currentState.selectItem(this);
}
public void dispense() {
currentState.dispense(this);
}
}
โ
Client.java
public class StatePatternDemo {
public static void main(String[] args) {
VendingMachine machine = new VendingMachine();
machine.selectItem(); // โ Insert coin first.
machine.insertCoin(); // ๐ช Coin inserted.
machine.insertCoin(); // โ Already inserted
machine.selectItem(); // ๐ฆ Dispensing
machine.dispense(); // โ
Dispensed, back to Idle
}
}
๐งช Output
โ Insert coin first.
๐ช Coin inserted. Ready to select item.
โ Coin already inserted.
๐ฆ Item selected. Dispensing now...
โ
Item dispensed. Back to idle.
โจ Benefits
| Benefit | Description |
|---|---|
| โ Open/Closed | Easily add new states without touching context |
| โ Clean code | No complex if-else for state logic |
| โ Maintainability | Each state is isolated, testable, reusable |
| โ Realistic modeling | Closer to real-world workflows |
โ ๏ธ Limitations
- โ Number of classes can grow with complex state machines
- โ ๏ธ Context object may need to expose internals (setState)
- ๐ May be overkill for simple linear flows
๐งพ Summary
| Aspect | Value |
|---|---|
| Pattern Type | Behavioral |
| Intent | Change behavior by state |
| Java Features Used | Interfaces, Polymorphism, Delegation |
| Ideal for | Workflow engines, UI flows, devices, FSMs |
๐ฏ Interview Tip
If asked to build a Ticket Booking System, Document Approval Workflow, or Game Character State, the State Pattern is often the cleanest and most extensible design choice.
Top comments (0)