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
Explanation of State Design Pattern's Class Diagram
OUTPUT on running Client.java
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 class for all the childConcreteState
classes.- The
Context
class holds a reference to theState
base class in an attribute namedstate
. In this attributeContext
stores the object of specificConcreteState
implementation corresponding to the state in which theContext
is currently. Client
invokes a request on theContext
class using itsrequest()
method.- When the
handle()
method is invoked on the base state reference stored in theContext
then the overloadedhandle()
method of the currentConcreteState
instance stored in it is executed. - Hence, the states show different behavior for the same
handle()
method invoked on theContext
based on the current state the system/context is in.
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();
}
}
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.
State
is the base interface which implements 3 methods -assignToDev
,assignToTester()
andmarkTested()
. These 3 methods represent the 3 transitions possible between states.- There are 4 concrete states -
NewState
,UnderDevState
,UnderTestState
andClosedState
. - The allowed transitions between states are -
NewState
toUnderDevState
transition is possible throughassignToDev()
.UnderDev
state toUnderTest
state transition is possible throughassignToTester()
.- In
UnderTest
state tester can transition the CR back toUnderDev
state if he finds an error usingassignToDev()
. If tester passes the CR then he transitions it toClosed
state usingmarkClosed()
.
- 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()
inNewState
without going throughUnderDev
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.
Gang of Four (GOF) Design Patterns on JavaBrahman
Creational Patterns: Factory method PatternFactory Method Design Pattern in Java Builder PatternBuilder Design Pattern in Java Prototype PatternPrototype Design Pattern in Java
Behavioral Patterns: Chain of Responsibility PatternChain of Responsibility Design Pattern in Java Observer PatternObserver Design Pattern in Java Iterator PatternIterator Design Pattern in Java State PatternState Design Pattern in Java Memento PatternMemento Design Pattern in Java Visitor PatternVisitor Design Pattern in Java Strategy PatternStrategy Design Pattern in Java Template Method PatternTemplate Method Design Pattern in Java
Structural Patterns: Adapter PatternAdapter design pattern in Java Composite PatternComposite Design Pattern in Java Facade PatternFacade Design Pattern in Java Proxy Pattern Java Proxy Design Pattern in Java
Analysis of Patterns: Strategy vs State PatternStrategy Design Pattern versus State Design Pattern
Creational Patterns: Factory method PatternFactory Method Design Pattern in Java Builder PatternBuilder Design Pattern in Java Prototype PatternPrototype Design Pattern in Java
Behavioral Patterns: Chain of Responsibility PatternChain of Responsibility Design Pattern in Java Observer PatternObserver Design Pattern in Java Iterator PatternIterator Design Pattern in Java State PatternState Design Pattern in Java Memento PatternMemento Design Pattern in Java Visitor PatternVisitor Design Pattern in Java Strategy PatternStrategy Design Pattern in Java Template Method PatternTemplate Method Design Pattern in Java
Structural Patterns: Adapter PatternAdapter design pattern in Java Composite PatternComposite Design Pattern in Java Facade PatternFacade Design Pattern in Java Proxy Pattern Java Proxy Design Pattern in Java
Analysis of Patterns: Strategy vs State PatternStrategy Design Pattern versus State Design Pattern