Easy Tutorial
❮ Command Pattern Front Controller Pattern ❯

State Pattern

In the State Pattern, the behavior of a class is based on its state. This type of design pattern falls under the category of behavioral patterns.

In the State Pattern, we create objects representing various states and a context object whose behavior varies as its state object changes.

Introduction

Intent: Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

Main Solution: The behavior of an object depends on its state and can change its behavior at runtime depending on that state.

When to Use: When the code contains a large number of conditionals related to the object's state.

How to Solve: Abstract the various concrete states into classes.

Key Code: Typically, the command pattern interface has only one method, while the state pattern interface has one or more methods. Furthermore, the methods of the state pattern's implementation classes usually return values or change instance variables. That is, the state pattern is generally related to the object's state. The methods of the implementation classes have different functionalities, overriding the methods in the interface. Like the command pattern, the state pattern can also be used to eliminate if...else conditional statements.

Application Examples:

  1. In basketball, an athlete can be in normal, abnormal, or super-normal states.
  2. In the Zeng Houyi Bells, 'Bell' is an abstract interface, 'Bell A' is a concrete state, and 'Zeng Houyi Bells' is the concrete context (Context).

Advantages:

  1. Encapsulates the transition rules.
  2. Enumerates possible states, which must be determined before enumerating.
  3. Puts all behaviors related to a state into one class, making it easy to add new states by changing the object's state.
  4. Allows state transition logic to be integrated with the state object, rather than being a large block of conditional statements.
  5. Allows multiple context objects to share a state object, reducing the number of objects in the system.

Disadvantages:

  1. The use of the state pattern will increase the number of system classes and objects.
  2. The structure and implementation of the state pattern are complex, and misuse can lead to confusion in program structure and code.
  3. The state pattern does not support the Open/Closed Principle well. For state patterns that can switch states, adding new states requires modifying the source code responsible for state transitions, otherwise, it cannot switch to the new state, and modifying the behavior of a state class also requires modifying the corresponding class's source code.

Usage Scenarios:

  1. Scenarios where behavior changes with state.
  2. Replacements for conditionals and branch statements.

Notes: Use the state pattern when behavior is constrained by state, and the number of states does not exceed five.

Implementation

We will create a State interface and concrete state classes that implement the State interface. A Context class will have a state.

StatePatternDemo, our demo class, will use Context and state objects to demonstrate the change in Context's behavior when the state changes.

Step 1

Create an interface.

State.java

public interface State {
   public void doAction(Context context);
}

Step 2

Create concrete classes implementing the interface.

StartState.java

public class StartState implements State {

   public void doAction(Context context) {
      System.out.println("Player is in start state");
      context.setState(this); 
   }

   public String toString(){
      return "Start State";
   }
}

StopState.java

public class StopState implements State {

   public void doAction(Context context) {
      System.out.println("Player is in stop state");
      context.setState(this); 
   }

   public String toString(){
      return "Stop State";
   }
}

Step 3

Create the Context class.

Context.java

public class Context {
   private State state;

   public Context(){
      state = null;
   }

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

   public State getState(){
      return state;
   }
}

Step 4

Use Context to see the behavior changes when State changes.

StatePatternDemo.java

public class StatePatternDemo {
   public static void main(String[] args) {
      Context context = new Context();

      StartState startState = new StartState();
      startState.doAction(context);

      System.out.println(context.getState().toString());

      StopState stopState = new StopState();
      stopState.doAction(context);

      System.out.println(context.getState().toString());
   }
}

Step 5

Execute the program, output results:

Player is in start state
Start State
Player is in stop state
Stop State

More Articles

-

Strategy Pattern vs State Pattern

❮ Command Pattern Front Controller Pattern ❯