DEV Community

DevCorner2
DevCorner2

Posted on

🧾 State Design Pattern – LLD + Java + Real-World Use Case

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)       |
+---------------------+       +------------------------+
Enter fullscreen mode Exit fullscreen mode

πŸ’» 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);
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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.");
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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.");
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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());
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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);
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ Output

❌ Insert coin first.
πŸͺ™ Coin inserted. Ready to select item.
❌ Coin already inserted.
πŸ“¦ Item selected. Dispensing now...
βœ… Item dispensed. Back to idle.
Enter fullscreen mode Exit fullscreen mode

✨ 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)