# How to Implement the State Pattern for Object Behavior Transitions in Java

> Learn to implement the State pattern in Java. This design pattern lets objects change behavior at runtime, simplifying complex conditional logic with state-specific classes.

- Repository: [Ilkka Seppälä/java-design-patterns](https://github.com/iluwatar/java-design-patterns)
- Tags: how-to-guide
- Published: 2026-02-27

---

**The State pattern allows an object to alter its behavior at runtime by delegating operations to state-specific classes, eliminating complex conditional logic.**

The State pattern is a behavioral design pattern that enables an object to change its behavior when its internal state changes, appearing as if the object changed its class. In the **iluwatar/java-design-patterns** repository, this pattern is demonstrated through a `Mammoth` that transitions between peaceful and angry moods. This guide shows you how to implement the State pattern for object behavior transitions in Java using the exact approach found in the reference implementation.

## State Pattern Architecture

The implementation consists of three core components that work together to encapsulate state-specific behavior and manage transitions.

- **State Interface**: Defines the contract that all concrete states must implement, ensuring consistent behavior across different states.
- **Concrete States**: Individual classes that implement the `State` interface, each containing behavior specific to that state.
- **Context**: The class that maintains a reference to the current state and delegates behavior to it, triggering transitions when conditions change.

## Step-by-Step Implementation

### Define the State Interface

Create an interface that declares the methods representing state-specific behavior. In [`state/src/main/java/com/iluwatar/state/State.java`](https://github.com/iluwatar/java-design-patterns/blob/main/state/src/main/java/com/iluwatar/state/State.java), the interface defines two methods: one for entry actions and one for the primary behavior.

```java
public interface State {
  void onEnterState();   // called when the context enters this state
  void observe();        // behavior exposed to the client
}

```

### Create Concrete State Classes

Implement the `State` interface for each distinct state. Each concrete state receives a reference to the context (`Mammoth`) in its constructor and implements state-specific behavior.

**PeacefulState.java** ([`state/src/main/java/com/iluwatar/state/PeacefulState.java`](https://github.com/iluwatar/java-design-patterns/blob/main/state/src/main/java/com/iluwatar/state/PeacefulState.java)):

```java
@Slf4j
public class PeacefulState implements State {
  private final Mammoth mammoth;
  
  public PeacefulState(Mammoth mammoth) { 
    this.mammoth = mammoth; 
  }

  @Override
  public void observe() {
    LOGGER.info("{} is calm and peaceful.", mammoth);
  }

  @Override
  public void onEnterState() {
    LOGGER.info("{} calms down.", mammoth);
  }
}

```

**AngryState.java** ([`state/src/main/java/com/iluwatar/state/AngryState.java`](https://github.com/iluwatar/java-design-patterns/blob/main/state/src/main/java/com/iluwatar/state/AngryState.java)):

```java
@Slf4j
public class AngryState implements State {
  private final Mammoth mammoth;
  
  public AngryState(Mammoth mammoth) { 
    this.mammoth = mammoth; 
  }

  @Override
  public void observe() {
    LOGGER.info("{} is furious!", mammoth);
  }

  @Override
  public void onEnterState() {
    LOGGER.info("{} gets angry!", mammoth);
  }
}

```

### Implement the Context Class

The context class ([`Mammoth.java`](https://github.com/iluwatar/java-design-patterns/blob/main/Mammoth.java) in [`state/src/main/java/com/iluwatar/state/Mammoth.java`](https://github.com/iluwatar/java-design-patterns/blob/main/state/src/main/java/com/iluwatar/state/Mammoth.java)) maintains the current state reference and handles transitions. It delegates behavior to the state object and encapsulates the transition logic.

```java
public class Mammoth {
  private State state;

  public Mammoth() {
    state = new PeacefulState(this);   // initial state
  }

  // Simulates the passage of time and flips the mood
  public void timePasses() {
    if (state.getClass().equals(PeacefulState.class)) {
      changeStateTo(new AngryState(this));
    } else {
      changeStateTo(new PeacefulState(this));
    }
  }

  private void changeStateTo(State newState) {
    this.state = newState;
    this.state.onEnterState();   // hook for entry actions
  }

  public void observe() {
    this.state.observe();        // delegate to current state
  }
}

```

### Handle State Transitions

Client code interacts with the context without knowing the specific state implementation. The `timePasses()` method triggers transitions, and the behavior changes dynamically.

```java
public static void main(String[] args) {
  var mammoth = new Mammoth();

  mammoth.observe();      // calm
  mammoth.timePasses(); // becomes angry
  mammoth.observe();      // furious
  mammoth.timePasses(); // back to calm
  mammoth.observe();      // calm again
}

```

**Output:**

```

The mammoth calms down.
The mammoth is calm and peaceful.
The mammoth gets angry!
The mammoth is furious!
The mammoth calms down.
The mammoth is calm and peaceful.

```

## Benefits of Using the State Pattern

Implementing the State pattern for object behavior transitions in Java provides several architectural advantages over traditional conditional approaches.

- **Eliminates conditional complexity**: Instead of `switch` statements or `if-else` chains checking state variables, behavior is encapsulated in separate classes.
- **Encapsulates state-specific behavior**: Each state class contains only the logic relevant to that state, improving cohesion and readability.
- **Open/Closed compliance**: Adding new states (such as `SleepState` or `HungryState`) requires only creating new classes that implement `State`; the `Mammoth` context requires no modification beyond the specific transition rule.
- **Dynamic behavior switching**: The context can switch states at runtime through methods like `timePasses()`, instantly changing observable behavior without changing the context's public interface.

## Summary

- The State pattern delegates behavior to state objects, allowing an object to change its behavior when its internal state changes.
- The implementation requires a **State interface** ([`State.java`](https://github.com/iluwatar/java-design-patterns/blob/main/State.java)), **concrete state classes** ([`PeacefulState.java`](https://github.com/iluwatar/java-design-patterns/blob/main/PeacefulState.java), [`AngryState.java`](https://github.com/iluwatar/java-design-patterns/blob/main/AngryState.java)), and a **context class** ([`Mammoth.java`](https://github.com/iluwatar/java-design-patterns/blob/main/Mammoth.java)) that maintains the current state.
- State transitions are handled within the context via methods like `changeStateTo()`, which updates the state reference and triggers entry actions via `onEnterState()`.
- This approach eliminates complex conditional logic, adheres to the Open/Closed Principle, and makes the codebase more maintainable and extensible.

## Frequently Asked Questions

### What is the difference between the State pattern and the Strategy pattern?

Both patterns use composition to delegate behavior to separate classes, but their intent differs. The **State pattern** manages state-specific behavior transitions where the object changes its behavior based on internal state changes, and the context often manages transitions between states. The **Strategy pattern** is used to select an algorithm at runtime based on client choice, where strategies are typically independent and interchangeable without the context managing transitions between them.

### How do you handle state transitions in the State pattern?

State transitions can be handled in two ways: either the **Context** class manages transitions (as shown in [`Mammoth.java`](https://github.com/iluwatar/java-design-patterns/blob/main/Mammoth.java) where `timePasses()` decides when to switch states), or the **Concrete State** classes themselves trigger transitions by calling back into the context. The approach used in the java-design-patterns implementation keeps transition logic centralized in the context, which prevents states from having dependencies on each other and makes the transition rules easier to modify.

### Can you add new states without modifying existing code?

Yes, the State pattern supports the **Open/Closed Principle**. You can add new states by creating new classes that implement the `State` interface without touching existing state classes. However, you may need to modify the **Context** class to include the new state in the transition graph—for example, adding a new condition in `timePasses()` or creating a new transition method. If you want to avoid modifying the context entirely, you can implement transitions within the state classes themselves, though this increases coupling between states.

### What are the advantages of using onEnterState() callbacks?

The `onEnterState()` method provides a **hook for entry actions** that execute immediately when a state becomes active. This is useful for initialization logic, logging state changes, or triggering side effects that should occur every time the system enters a particular state. In the Mammoth example, this method logs mood changes ("calms down" or "gets angry"), providing clear visibility into state transitions without cluttering the business logic in the context or client code.