Java Language – 91 – State

Design Patterns – State
Introduction to the State Design Pattern

The State pattern is a behavioral design pattern that allows an object to alter its behavior when its internal state changes. The pattern encapsulates the different behaviors into separate state classes and delegates the behavior to the current state. This approach is useful when an object has multiple behaviors that depend on its internal state.

Key Components of the State Pattern

The State pattern involves the following key components:

  • Context: The Context is the object that maintains a reference to the current state. It also triggers state transitions by calling methods on the state objects. The context delegates the specific behavior to the current state.
  • State: The State is an interface or an abstract class that defines the common interface for all concrete state classes. It declares methods for actions that can vary based on the state.
  • Concrete State: Concrete State classes implement the State interface. They provide specific implementations of the methods defined in the State interface. Each concrete state represents a specific behavior associated with a particular state of the context.
Implementing the State Pattern

Let’s illustrate the State pattern with a simple example in Java. We will create a traffic light simulation where the traffic light can be in one of three states: Red, Yellow, or Green.


// State interface
interface TrafficLightState {
    void handleRequest();
}

// Concrete State classes
class RedLightState implements TrafficLightState {
    public void handleRequest() {
        System.out.println("Turning to Green.");
    }
}

class YellowLightState implements TrafficLightState {
    public void handleRequest() {
        System.out.println("Turning to Red.");
    }
}

class GreenLightState implements TrafficLightState {
    public void handleRequest() {
        System.out.println("Turning to Yellow.");
    }
}

// Context
class TrafficLight {
    private TrafficLightState state;

    public TrafficLight() {
        // Initialize with the Red state
        this.state = new RedLightState();
    }

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

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

// Client
public class StatePatternExample {
    public static void main(String[] args) {
        TrafficLight trafficLight = new TrafficLight();

        trafficLight.change(); // Red to Green
        trafficLight.change(); // Green to Yellow
        trafficLight.change(); // Yellow to Red
    }
}

In this example, we have a TrafficLightState interface and three concrete state classes: RedLightState, YellowLightState, and GreenLightState. The TrafficLight class maintains the current state and delegates the change operation to the current state. The client triggers state transitions by calling the change method.

Usage of the State Pattern

The State pattern is useful in scenarios where an object can change its behavior based on internal state changes. It simplifies the management of complex state-dependent logic and reduces conditional statements.

Benefits of the State Pattern

The State pattern offers several advantages:

  • Clean Separation: It cleanly separates the behavior of an object into distinct state classes, making the code more organized and maintainable.
  • Open/Closed Principle: It follows the open/closed principle, allowing you to add new states without modifying existing code.
  • Behavior Encapsulation: Each state class encapsulates its behavior, making it easy to understand and modify.
Comparison with Other Patterns

The State pattern is often compared to the Strategy pattern. Both patterns allow an object to change its behavior dynamically. However, the State pattern focuses on encapsulating the state-specific behavior, while the Strategy pattern focuses on providing different algorithms or strategies.

Conclusion

The State pattern is a valuable tool for managing state-dependent behavior in an object-oriented system. It promotes clean code, flexibility, and extensibility, making it a useful design pattern in Java and other programming languages.