Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

State Pattern - Design Patterns

1. Introduction

The State Pattern is a behavioral design pattern that allows an object to alter its behavior when its internal state changes. It is particularly useful when an object can be in multiple states, each affecting its behavior.

2. Definition

The State Pattern encapsulates state-specific behavior in separate classes and delegates the task of handling the state-specific behavior to the current state object.

Key Takeaway: Instead of having a series of conditional statements to manage state, the pattern uses a suite of classes representing the different states.

3. Structure

The State Pattern consists of the following components:

  • Context: The class that contains a reference to a State object.
  • State: An interface or abstract class defining the methods that concrete states must implement.
  • Concrete States: Classes that implement the State interface, defining specific behaviors for each state.

Diagram:


graph TD;
    A[Context] -->|contains| B[State]
    B -->|implemented by| C[Concrete State 1]
    B -->|implemented by| D[Concrete State 2]
    

4. Implementation

Here is an example of the State Pattern in a simple traffic light system:


class TrafficLightState {
    public void change(TrafficLight context) {}
}

class RedLight extends TrafficLightState {
    public void change(TrafficLight context) {
        System.out.println("Red Light - Stop");
        context.setState(new GreenLight());
    }
}

class GreenLight extends TrafficLightState {
    public void change(TrafficLight context) {
        System.out.println("Green Light - Go");
        context.setState(new YellowLight());
    }
}

class YellowLight extends TrafficLightState {
    public void change(TrafficLight context) {
        System.out.println("Yellow Light - Slow Down");
        context.setState(new RedLight());
    }
}

class TrafficLight {
    private TrafficLightState currentState;

    public TrafficLight(TrafficLightState state) {
        this.currentState = state;
    }

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

    public void change() {
        currentState.change(this);
    }
}

public class Main {
    public static void main(String[] args) {
        TrafficLight light = new TrafficLight(new RedLight());
        for (int i = 0; i < 5; i++) {
            light.change();
        }
    }
}
                

5. Best Practices

When implementing the State Pattern, keep the following best practices in mind:

  • Encapsulate state-specific behaviors in separate classes.
  • Keep the context class lean to avoid bloating with state logic.
  • Use the State Pattern when you have multiple states that affect behavior.
  • Ensure that state transitions are clear and well-defined.

6. FAQ

What is the main benefit of using the State Pattern?

The main benefit is the elimination of large conditional statements and making the code more maintainable and extensible.

Can the State Pattern be used in all situations?

It's not always necessary; use it when an object has distinct states that significantly change its behavior.

Is it possible to have nested states?

Yes, you can have states that contain other states, but it can complicate the design.