State Design Pattern

Last Updated : 13 Feb, 2026

The State Design Pattern is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It encapsulates state-specific behavior into separate state classes, allowing the object to manage state transitions cleanly. This avoids complex conditional statements and makes the system more maintainable and flexible.

  • Allows an object’s behavior to change dynamically based on its state
  • Encapsulates state-specific behavior in separate classes
  • Simplifies management of state transitions
  • Improves code maintainability and extensibility

For example, a vending machine responds differently based on state (item selected, money paid and item dispensed).

state_design_pattern
State Design Pattern

Uses

The State pattern is commonly used when an object’s behavior depends on its state and changes over time.

  • Vending machines (item selected, money inserted, item dispensed)
  • Traffic light systems (green, yellow, red states)
  • Media players (playing, paused, stopped states)
  • Workflow systems where tasks progress through different states

Working

The pattern works by encapsulating each possible state in a separate class and letting the context object delegate behavior to the current state.

  • The context (main object) holds a reference to the current state
  • Each state class defines behavior specific to that state
  • When the context’s state changes, it switches the state object, automatically changing its behavior
  • Clients interact with the context without needing to know the current state

Components

The State pattern is structured around components that separate state-specific behavior from the main object, allowing behavior to change dynamically at runtime.

  • Context – Maintains a reference to the current state, delegates behavior to it, and provides an interface for clients.
  • State Interface/Base Class – Defines common methods for all states, allowing Context to work with them without knowing concrete types.
  • Concrete States – Implement the State interface, encapsulating behavior for specific states and defining Context’s actions in those states.

componentdiagramstate

Example

Problem Statement:

Imagine a vending machine that sells various products. The vending machine needs to manage different states such as ready to serve, waiting for product selection, processing payment, and handling out-of-stock situations. Design a system that models the behavior of this vending machine efficiently.

How State Design Pattern will help while building this system:

  • Modeling States – Each state (Ready, Product Selected, Payment Pending, Out of Stock) is represented as a separate class, keeping the code organized.
  • Encapsulation – Each state class defines its own behavior (e.g., ReadyState handles selection, PaymentPendingState handles payments), simplifying complex logic.
  • Dynamic Transitions – The machine moves between states (e.g., Ready → Product Selected → Payment Pending) based on user actions.
  • Reusability – State classes can be reused across different vending machine implementations, reducing duplication.
  • Maintainability & Flexibility – New states or changes can be added without impacting other parts, making the system easier to extend and maintain.

User Interaction with the System

User interactions with the vending machine trigger state transitions. For example, when a user inserts money, the vending machine transitions from the "ReadyState" to the "PaymentPendingState." Similarly, when a product is selected, the vending machine transitions to the "ProductSelectedState." If a product is out of stock, the vending machine transitions to the "OutOfStockState."

ClassDiagramState

Implementation of above Example

Let’s break down into the component wise code:

1. Context(VendingMachineContext)

The context is responsible for maintaining the current state of the vending machine and delegating state-specific behavior to the appropriate state object.

C++
public class VendingMachineContext {
    private VendingMachineState state;

    public void setState(VendingMachineState state) {
        this.state = state;
    }

    public void request() {
        state.handleRequest();
    }
}
Java
public class VendingMachineContext {
    private VendingMachineState state;

    public void setState(VendingMachineState state) {
        this.state = state;
    }

    public void request() {
        state.handleRequest();
    }
}
Python
class VendingMachineContext:
    def __init__(self):
        self._state = None

    def set_state(self, state):
        self._state = state

    def request(self):
        self._state.handle_request()
JavaScript
class VendingMachineContext {
    #private VendingMachineState state;

    constructor() {
        this.state = null;
    }

    setState(state) {
        this.state = state;
    }

    request() {
        this.state.handleRequest();
    }
}

2. State Interface (VendingMachineState)

This interface defines the contract that all concrete state classes must implement. It typically contains a method or methods representing the behavior associated with each state of the vending machine.

C++
public interface VendingMachineState {
    void handleRequest();
}
Java
/* Public interface VendingMachineState */
public interface VendingMachineState {
    void handleRequest();
}
Python
""" Public interface VendingMachineState """
from abc import ABC, abstractmethod

class VendingMachineState(ABC):
    @abstractmethod
    def handleRequest(self):
        pass
JavaScript
/* Public interface VendingMachineState */
class VendingMachineState {
    handleRequest() {
        // Handle request logic here
    }
}

3. Concrete States (Specific Vending Machine States)

Concrete state classes represent specific states of the vending machine, such as "ReadyState," "ProductSelectedState," and "OutOfStockState." Each concrete state class implements the behavior associated with its respective state, like allowing product selection, processing payment, or displaying an out-of-stock message.

C++
#include <iostream>
#include <string>
using namespace std;

class VendingMachineState {
public:
    virtual void handleRequest() = 0;
};

class ReadyState : public VendingMachineState {
public:
    void handleRequest() override {
        cout << "Ready state: Please select a product." << endl;
    }
};

class ProductSelectedState : public VendingMachineState {
public:
    void handleRequest() override {
        cout << "Product selected state: Processing payment." << endl;
    }
};

class PaymentPendingState : public VendingMachineState {
public:
    void handleRequest() override {
        cout << "Payment pending state: Dispensing product." << endl;
    }
};

class OutOfStockState : public VendingMachineState {
public:
    void handleRequest() override {
        cout << "Out of stock state: Product unavailable. Please select another product." << endl;
    }
};
Java
import java.util.ArrayList;

// VendingMachineState interface
interface VendingMachineState {
    void handleRequest();
}

// ReadyState class
class ReadyState implements VendingMachineState {
    @Override
    public void handleRequest() {
        System.out.println("Ready state: Please select a product.");
    }
}

// ProductSelectedState class
class ProductSelectedState implements VendingMachineState {
    @Override
    public void handleRequest() {
        System.out.println("Product selected state: Processing payment.");
    }
}

// PaymentPendingState class
class PaymentPendingState implements VendingMachineState {
    @Override
    public void handleRequest() {
        System.out.println("Payment pending state: Dispensing product.");
    }
}

// OutOfStockState class
class OutOfStockState implements VendingMachineState {
    @Override
    public void handleRequest() {
        System.out.println("Out of stock state: Product unavailable. Please select another product.");
    }
}

// VendingMachine class
class VendingMachine {
    private VendingMachineState currentState;

    public VendingMachine() {
        this.currentState = new ReadyState();
    }

    public void setState(VendingMachineState state) {
        this.currentState = state;
    }

    public void handleRequest() {
        currentState.handleRequest();
    }
}

// Main class
public class Main {
    public static void main(String[] args) {
        VendingMachine vendingMachine = new VendingMachine();
        vendingMachine.handleRequest();
        vendingMachine.setState(new ProductSelectedState());
        vendingMachine.handleRequest();
        vendingMachine.setState(new PaymentPendingState());
        vendingMachine.handleRequest();
        vendingMachine.setState(new OutOfStockState());
        vendingMachine.handleRequest();
    }
}
Python
from abc import ABC, abstractmethod

class VendingMachineState(ABC):
    @abstractmethod
    def handle_request(self):
        pass

class ReadyState(VendingMachineState):
    def handle_request(self):
        print('Ready state: Please select a product.')

class ProductSelectedState(VendingMachineState):
    def handle_request(self):
        print('Product selected state: Processing payment.')

class PaymentPendingState(VendingMachineState):
    def handle_request(self):
        print('Payment pending state: Dispensing product.')

class OutOfStockState(VendingMachineState):
    def handle_request(self):
        print('Out of stock state: Product unavailable. Please select another product.')
JavaScript
class VendingMachineState {}

class ReadyState extends VendingMachineState {
    handleRequest() {
        console.log('Ready state: Please select a product.');
    }
}

class ProductSelectedState extends VendingMachineState {
    handleRequest() {
        console.log('Product selected state: Processing payment.');
    }
}

class PaymentPendingState extends VendingMachineState {
    handleRequest() {
        console.log('Payment pending state: Dispensing product.');
    }
}

class OutOfStockState extends VendingMachineState {
    handleRequest() {
        console.log('Out of stock state: Product unavailable. Please select another product.');
    }
}

Complete code for the above example

Below is the complete code for the above example:

C++
#include <iostream>

class VendingMachineState {
public:
    virtual void handleRequest() = 0;
};

class ReadyState : public VendingMachineState {
public:
    void handleRequest() override {
        std::cout << "Ready state: Please select a product." << std::endl;
    }
};

class ProductSelectedState : public VendingMachineState {
public:
    void handleRequest() override {
        std::cout << "Product selected state: Processing payment." << std::endl;
    }
};

class PaymentPendingState : public VendingMachineState {
public:
    void handleRequest() override {
        std::cout << "Payment pending state: Dispensing product." << std::endl;
    }
};

class OutOfStockState : public VendingMachineState {
public:
    void handleRequest() override {
        std::cout << "Out of stock state: Product unavailable. Please select another product." << std::endl;
    }
};

class VendingMachineContext {
private:
    VendingMachineState* state;
public:
    void setState(VendingMachineState* state) {
        this->state = state;
    }
    void request() {
        state->handleRequest();
    }
};

int main() {
    VendingMachineContext vendingMachine;

    vendingMachine.setState(new ReadyState());
    vendingMachine.request();

    vendingMachine.setState(new ProductSelectedState());
    vendingMachine.request();

    vendingMachine.setState(new PaymentPendingState());
    vendingMachine.request();

    vendingMachine.setState(new OutOfStockState());
    vendingMachine.request();

    return 0;
}
Java
interface VendingMachineState {
    void handleRequest();
}

class ReadyState implements VendingMachineState {
    @Override
    public void handleRequest() {
        System.out.println("Ready state: Please select a product.");
    }
}

class ProductSelectedState implements VendingMachineState {
    @Override
    public void handleRequest() {
        System.out.println("Product selected state: Processing payment.");
    }
}

class PaymentPendingState implements VendingMachineState {
    @Override
    public void handleRequest() {
        System.out.println("Payment pending state: Dispensing product.");
    }
}

class OutOfStockState implements VendingMachineState {
    @Override
    public void handleRequest() {
        System.out.println("Out of stock state: Product unavailable. Please select another product.");
    }
}

class VendingMachineContext {
    private VendingMachineState state;

    public void setState(VendingMachineState state) {
        this.state = state;
    }

    public void request() {
        state.handleRequest();
    }
}

public class Main {
    public static void main(String[] args) {
        // Create context
        VendingMachineContext vendingMachine = new VendingMachineContext();

        // Set initial state
        vendingMachine.setState(new ReadyState());

        // Request state change
        vendingMachine.request();

        // Change state
        vendingMachine.setState(new ProductSelectedState());

        // Request state change
        vendingMachine.request();

        // Change state
        vendingMachine.setState(new PaymentPendingState());

        // Request state change
        vendingMachine.request();

        // Change state
        vendingMachine.setState(new OutOfStockState());

        // Request state change
        vendingMachine.request();
    }
}
Python
from abc import ABC, abstractmethod

class VendingMachineState(ABC):
    @abstractmethod
    def handle_request(self):
        pass

class ReadyState(VendingMachineState):
    def handle_request(self):
        print("Ready state: Please select a product.")

class ProductSelectedState(VendingMachineState):
    def handle_request(self):
        print("Product selected state: Processing payment.")

class PaymentPendingState(VendingMachineState):
    def handle_request(self):
        print("Payment pending state: Dispensing product.")

class OutOfStockState(VendingMachineState):
    def handle_request(self):
        print("Out of stock state: Product unavailable. Please select another product.")

class VendingMachineContext:
    def __init__(self):
        self.state = None

    def set_state(self, state):
        self.state = state

    def request(self):
        self.state.handle_request()

def main():
    # Create context
    vending_machine = VendingMachineContext()

    # Set initial state
    vending_machine.set_state(ReadyState())

    # Request state change
    vending_machine.request()

    # Change state
    vending_machine.set_state(ProductSelectedState())

    # Request state change
    vending_machine.request()

    # Change state
    vending_machine.set_state(PaymentPendingState())

    # Request state change
    vending_machine.request()

    # Change state
    vending_machine.set_state(OutOfStockState())

    # Request state change
    vending_machine.request()

if __name__ == "__main__":
    main()
JavaScript
class VendingMachineState {
    handleRequest() {
        throw new Error('Method handleRequest must be implemented.');
    }
}

class ReadyState extends VendingMachineState {
    handleRequest() {
        console.log('Ready state: Please select a product.');
    }
}

class ProductSelectedState extends VendingMachineState {
    handleRequest() {
        console.log('Product selected state: Processing payment.');
    }
}

class PaymentPendingState extends VendingMachineState {
    handleRequest() {
        console.log('Payment pending state: Dispensing product.');
    }
}

class OutOfStockState extends VendingMachineState {
    handleRequest() {
        console.log('Out of stock state: Product unavailable. Please select another product.');
    }
}

class VendingMachineContext {
    constructor() {
        this.state = null;
    }

    setState(state) {
        this.state = state;
    }

    request() {
        this.state.handleRequest();
    }
}

function main() {
    // Create context
    const vendingMachine = new VendingMachineContext();

    // Set initial state
    vendingMachine.setState(new ReadyState());

    // Request state change
    vendingMachine.request();

    // Change state
    vendingMachine.setState(new ProductSelectedState());

    // Request state change
    vendingMachine.request();

    // Change state
    vendingMachine.setState(new PaymentPendingState());

    // Request state change
    vendingMachine.request();

    // Change state
    vendingMachine.setState(new OutOfStockState());

    // Request state change
    vendingMachine.request();
}

main();

Output
Ready state: Please select a product.
Product selected state: Processing payment.
Payment pending state: Dispensing product.
Out of stock state: Product unavailable. Please select another product.

Real Life Software Examples

The State pattern can be observed in many real-world applications where an object’s behavior changes depending on its current condition.

  • Media Player behaves differently in each play, pause and stop states. The internal state determines what action happens when a button is pressed. For example, in play state, it responds to pause and stop.
  • Document (Google Docs and MS Word) respond differently according to the current status of the document. In Draft: only the author can edit. In Review: reviewers can comment, but not edit and in Published: it becomes read-only.

Advantages

This pattern makes state-dependent behavior easier to manage and extend.

  • Eliminates large conditional statements for state handling
  • Makes it easy to add or modify states without affecting existing code
  • Improves code readability and maintainability
  • Supports dynamic behavior changes at runtime

Disadvantages

Despite its benefits, it has some drawbacks.

  • Increases the number of classes in the system
  • Can add unnecessary complexity for objects with few states
  • State transitions can become harder to track in large systems
Comment

Explore