Menu
Coddy logo textTech

State Pattern

Part of the Object Oriented Programming section of Coddy's Java journey — lesson 74 of 87.

The State Pattern is a behavioral design pattern that allows an object to change its behavior when its internal state changes. The object appears to change its class, but in reality, it delegates behavior to different state objects. Think of a vending machine: its response to pressing a button depends on whether it's idle, has money inserted, or is dispensing a product.

Instead of using complex conditional statements to handle different states, you encapsulate each state in its own class. The pattern involves a Context that maintains a reference to the current state, and State classes that define behavior for each state:

interface State {
    void handle(Context context);
}

class Context {
    private State state;
    
    public void setState(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }
}

Each concrete state implements the behavior and can trigger transitions to other states:

class IdleState implements State {
    public void handle(Context context) {
        System.out.println("Idle: Insert coin to start");
        context.setState(new ActiveState());
    }
}

class ActiveState implements State {
    public void handle(Context context) {
        System.out.println("Active: Processing...");
        context.setState(new IdleState());
    }
}

The context delegates requests to its current state, and the behavior changes automatically as the state changes:

Context context = new Context();
context.setState(new IdleState());

context.request();  // Idle: Insert coin to start
context.request();  // Active: Processing...

The State Pattern is ideal when an object's behavior depends heavily on its state and must change at runtime. It eliminates large conditional blocks and makes adding new states straightforward—just create a new class implementing the State interface.

challenge icon

Challenge

Easy

Let's build a document workflow system using the State Pattern! You'll create a system that models how a document moves through different stages—Draft, Review, and Published—with each state determining what actions are available and how the document behaves when you try to edit or approve it.

You'll organize your code across four files:

  • DocumentState.java: Define the DocumentState interface that all states will implement. It should declare two methods: edit(Document doc) for attempting to edit the document, and approve(Document doc) for attempting to approve/advance the document to the next stage.
  • States.java: Create three concrete state classes that implement DocumentState:

    DraftState - When edit is called, print Editing draft.... When approve is called, print Draft approved. Moving to review. and transition the document to ReviewState.

    ReviewState - When edit is called, print Cannot edit during review. (no state change). When approve is called, print Review complete. Publishing document. and transition to PublishedState.

    PublishedState - When edit is called, print Cannot edit published document.. When approve is called, print Document already published.. Neither action changes the state.

  • Document.java: Create the context class that maintains the current state. Your Document should have:

    A private field holding the current DocumentState, initialized to DraftState in the constructor.

    A setState(DocumentState state) method that changes the current state.

    An edit() method that delegates to the current state's edit method.

    An approve() method that delegates to the current state's approve method.

    A getStatus() method that returns the simple class name of the current state (use getClass().getSimpleName()).

  • Main.java: Demonstrate your state system! You'll receive one input: a sequence of actions as a comma-separated string where each action is either edit or approve (for example: edit,approve,edit,approve).

    Create a Document and print its initial status in the format Status: [state]. Then process each action in order, calling the appropriate method on the document. After each action, print the current status.

You will receive one input: a comma-separated string of actions.

For example, with input edit,approve,approve, your output would be:

Status: DraftState
Editing draft...
Status: DraftState
Draft approved. Moving to review.
Status: ReviewState
Review complete. Publishing document.
Status: PublishedState

Notice how the same approve() call produces different results depending on the document's current state—this is the essence of the State Pattern! The document doesn't use conditionals to check its state; instead, it delegates behavior to the current state object, which handles the action appropriately and triggers transitions when needed.

Cheat sheet

The State Pattern is a behavioral design pattern that allows an object to change its behavior when its internal state changes by delegating behavior to different state objects instead of using complex conditional statements.

The pattern consists of a Context that maintains a reference to the current state, and State classes that define behavior for each state:

interface State {
    void handle(Context context);
}

class Context {
    private State state;
    
    public void setState(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }
}

Each concrete state implements the behavior and can trigger transitions to other states:

class IdleState implements State {
    public void handle(Context context) {
        System.out.println("Idle: Insert coin to start");
        context.setState(new ActiveState());
    }
}

class ActiveState implements State {
    public void handle(Context context) {
        System.out.println("Active: Processing...");
        context.setState(new IdleState());
    }
}

The context delegates requests to its current state, and behavior changes automatically as the state changes:

Context context = new Context();
context.setState(new IdleState());

context.request();  // Idle: Insert coin to start
context.request();  // Active: Processing...

The State Pattern is ideal when an object's behavior depends heavily on its state and must change at runtime. It eliminates large conditional blocks and makes adding new states straightforward.

Try it yourself

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Create a new Document
        
        // TODO: Print the initial status in format "Status: [state]"
        
        // TODO: Split the input by comma to get individual actions
        
        // TODO: Loop through each action
        // - If action is "edit", call edit() on document
        // - If action is "approve", call approve() on document
        // - After each action, print the current status
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming