JB Header
State Design Pattern in Java
This article explains State design pattern in java with UML class diagram. It then takes an example scenario in java and explains it with class diagram and code. Introduction State Design Pattern is a behavioral design pattern among the Gang Of Four(GOF) Design PatternsArticle on GOF Patterns & their types. Being a behavioral design pattern, the State pattern deals with how the objects communicate and share responsibilities among each other. What is State Design Pattern State Design Pattern allows the behavior of an object to vary based on its state. I.e. whenever the object's state changes, its behavior changes as per its new state. To the observer it appears as if the object has changed its class. Important advantage of State Design Pattern If there are state-based scenarios in a system where the different states of an object are implemented via multiple sets of conditional statements. And each set of conditional statements is applied based on the condition that the object is in the state corresponding to those statements. In such scenarios, instead of writing multiple if-else blocks for each of the states and juggling with the various state dependent values, it becomes much easier to encapsulate each of these set of statements into separate classes of their own. The implementation of each state can thus vary independently of the other states.
Class Diagram for State Design Pattern
State Design Pattern Class Diagram
Explanation of State Design Pattern's Class Diagram
  • State is the base class for all the child ConcreteState classes.
  • The Context class holds a reference to the State base class in an attribute named state. In this attribute Context stores the object of specific ConcreteState implementation corresponding to the state in which the Context is currently.
  • Client invokes a request on the Context class using its request() method.
  • When the handle() method is invoked on the base state reference stored in the Context then the overloaded handle() method of the current ConcreteState instance stored in it is executed.
  • Hence, the states show different behavior for the same handle() method invoked on the Context based on the current state the system/context is in.
State Design Pattern in Java - Class Diagram
State Design Pattern in Java Class Diagram

Code for the classes shown in Java Example’s Class Diagram
public interface State{
 public void assignToDev();
 public void assignToTester();
 public void markTested();
}
public class ChangeRequestContext {
  State newState;
  State underDevState;
  State underTestState;
  State closedState;
  State currentState = new NewState(this);
  public ChangeRequestContext() {
    newState = new NewState(this);
    underDevState = new UnderDevState(this);
    underTestState = new UnderTestState(this);
    closedState = new ClosedState(this);
  }
  public void assignToDev() {
    currentState.assignToDev();
  }
  public void assignToTester() {
    currentState.assignToTester();
  }
  public void markTested() {
    currentState.markTested();
  }
  //setters and getters for the 4 States' attribute & the currentState attribute
}
public class NewState implements State {
  private ChangeRequestContext CRSystem;
  public NewState(ChangeRequestContext CRSystem) {
    this.CRSystem = CRSystem;
  }
  public void assignToDev() {
    System.out.println("Assigning to available developer.");
   this.CRSystem.setCurrentState(CRSystem.getUnderDevState());
  }
  public void assignToTester() {
    System.out.println("Cannot be assigned to tester from new state.");
  }
  public void markTested() {
   System.out.println("Cannot be marked tested when it is new.");
  }
}
public class UnderDevState implements State{
  private ChangeRequestContext CRSystem;
  public UnderDevState(ChangeRequestContext CRSystem){
    this.CRSystem=CRSystem;
  }  
  public void assignToDev(){
    System.out.println("It's already assigned to a developer.");
  }  
  public void assignToTester(){
    System.out.println("Assigning to available tester.");
    this.CRSystem.setCurrentState(CRSystem.getUnderTestState());
  }  
  public void markTested(){
	  System.out.println("Cannot be marked tested when it is under dev.");  	  
  }
}
public class UnderTestState implements State{
  private ChangeRequestContext CRSystem;
  public UnderTestState(ChangeRequestContext CRSystem) {
    this.CRSystem = CRSystem;
  }
  public void assignToDev() {
    System.out.println("Assigning Back to Developer.");
    this.CRSystem.setCurrentState(CRSystem.getUnderDevState());
  }
  public void assignToTester() {
     System.out.println("Cannot be done as already under test.");
  }
  public void markTested() {
    System.out.println("Marking as tested.");
 	this.CRSystem.setCurrentState(CRSystem.getClosedState());
  }
}
public class ClosedState implements State{
  private ChangeRequestContext CRSystem;
  public ClosedState(ChangeRequestContext CRSystem) {
    this.CRSystem = CRSystem;
  }
  public void assignToDev() {
    System.out.println("Cannot be done as CR is closed.");
  }
  public void assignToTester() {
    System.out.println("Cannot be done as CR is closed.");
  }
  public void markTested() {
    System.out.println("Cannot be done as CR is closed.");
  }
}
public class Client {
  public static void main(String args[]){
    ChangeRequestContext CRSystem=new ChangeRequestContext();
    CRSystem.assignToTester();
    CRSystem.assignToDev();
    CRSystem.markTested();
    CRSystem.assignToTester();
    CRSystem.assignToDev();
    CRSystem.assignToTester();
    CRSystem.markTested();
  }
}
 OUTPUT on running Client.java
Cannot be assigned to tester from new state.
Assigning to available developer.
Cannot be marked tested when it is under dev.
Assigning to available tester.
Assigning Back to Developer.
Assigning to available tester.
Marking as tested.
Explanation of Java Example’s Class Diagram & Code The Java class diagram above depicts State Design pattern implemented for a ChangeRequest State Handler. Lets quickly go through whats there in UML class diagram & corresponding code -
  • State is the base interface which implements 3 methods - assignToDev, assignToTester() and markTested(). These 3 methods represent the 3 transitions possible between states.
  • There are 4 concrete states - NewState, UnderDevState, UnderTestState and ClosedState.
  • The allowed transitions between states are -
    • NewState to UnderDevState transition is possible through assignToDev().
    • UnderDev state to UnderTest state transition is possible through assignToTester().
    • In UnderTest state tester can transition the CR back to UnderDev state if he finds an error using assignToDev(). If tester passes the CR then he transitions it to Closed state using markClosed().
  • The Client invokes series of transitions in sequence. Some transitions are valid and move the CR to the next state. For eg: When moving from New to UnderDev the following is output - Assigning to available developer.
  • There are also some invalid transitions such as invoking assignToTester() in NewState without going through UnderDev state in which case the line Cannot be assigned to tester from new state - is printed.
  • Thus, a CR moves through the states - New > UnderDev > UnderTest > Closed during its lifecycle.
Summary In the above tutorial we understood what is State design pattern and its main advantage. We then looked at the UML class diagram for State Design Pattern & its explanation, a Java Use Case implementing State pattern with its class diagram and code for the classes shown in the class diagram, followed by explanation of both the class diagram & code. This concludes the tutorial on State design pattern.