State Pattern

State design pattern is one of the behavioural design patterns.

This pattern is used when an Object changes its behaviour based on its internal state.

Example :

Assume some electronic device is an object which has 2 states called “ON” and “OFF”

This object behaves differently when the state changes.

When the state is “ON” it will turn on the device and when the state is “OFF” it will turn off the device

If we want to execute different behaviour based on state change, we can do it using if-else conditions

But, State pattern provides the solution for the same in a more loosely coupled way.

State pattern uses 2 important concepts called “context” and “State” to achieve the same.

state_pattern

Let’s understand these 2 concepts

State defines a class with separate implementations for each behaviour with parent abstract class or Interface

Context is the class that has a reference to one of the concrete implementations of the State.

Context forwards the request to the state object for processing

Let’s try to understand State pattern with example


Consider above example of electronic device, it has 2 states “ON” and “OFF”

Based on the state, corresponding behaviour of the device will change

If we implement this requirement without state pattern, we need to use if-else blocks as below

  1. package com.kb.state;
  2.  
  3.  
  4. public class ElectronicDevice {
  5.  
  6.     private String state;
  7.    
  8.     public void setState(String state){
  9.         this.state=state;
  10.     }
  11.    
  12.     public void execute(){
  13.         if(state.equalsIgnoreCase("ON")){
  14.             System.out.println("Device is turned ON");
  15.         }else if(state.equalsIgnoreCase("OFF")){
  16.             System.out.println("Device is turned OFF");
  17.         }
  18.     }
  19.  
  20.     public static void main(String args[]){
  21.         ElectronicDevice device = new ElectronicDevice();
  22.        
  23.         device.setState("ON");
  24.         device.execute();
  25.        
  26.         device.setState("OFF");
  27.         device.execute();
  28.     }
  29.  
  30. }
package com.kb.state;


public class ElectronicDevice {

	private String state;
	
	public void setState(String state){
		this.state=state;
	}
	
	public void execute(){
		if(state.equalsIgnoreCase("ON")){
			System.out.println("Device is turned ON");
		}else if(state.equalsIgnoreCase("OFF")){
			System.out.println("Device is turned OFF");
		}
	}

	public static void main(String args[]){
		ElectronicDevice device = new ElectronicDevice();
		
		device.setState("ON");
		device.execute();
		
		device.setState("OFF");
		device.execute();
	}

}



If we observe this implementation, we could see that, if-else condition is tightly coupled with states.

Let’s try to implement the same using State design pattern

Step 1

First of all, We need to create State interface

This will define the method that should be implemented by different concrete states classes and context class.

  1. package com.kb.state;
  2.  
  3. public interface State {
  4.     public void execute();
  5. }
package com.kb.state;

public interface State {
	public void execute();
}


We have defined State interface and declared a method called “execute()”

Step 2

In our requirement, we will have 2 states – one for turning Device on and another to turn it off.

So, we need to create 2 concrete state implementations for these behaviours.

  1. package com.kb.state;
  2.  
  3. public class DeviceOnState implements State {
  4.  
  5.     @Override
  6.     public void execute() {
  7.         System.out.println("Device is turned ON");
  8.     }
  9.  
  10. }
  11.  
  12. package com.kb.state;
  13.  
  14. public class DeviceOffState  implements State {
  15.  
  16.     @Override
  17.     public void execute() {
  18.         System.out.println("Device is turned OFF");
  19.     }
  20.  
  21. }
package com.kb.state;

public class DeviceOnState implements State {

	@Override
	public void execute() {
		System.out.println("Device is turned ON");
	}

}

package com.kb.state;

public class DeviceOffState  implements State {

	@Override
	public void execute() {
		System.out.println("Device is turned OFF");
	}

}

Step 3

Create a context class which implements State and holds a reference to State object

  1. package com.kb.state;
  2.  
  3. public class DeviceContext implements State {
  4.  
  5.     private State state;
  6.  
  7.     @Override
  8.     public void execute() {
  9.         state.execute();
  10.     }
  11.  
  12.     public State getState() {
  13.         return state;
  14.     }
  15.  
  16.     public void setState(State state) {
  17.         this.state = state;
  18.     }
  19. }
package com.kb.state;

public class DeviceContext implements State {

	private State state;

	@Override
	public void execute() {
		state.execute();
	}

	public State getState() {
		return state;
	}

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


We can see that Context class holds a reference to current state and makes a request to actual state implementation

Step 4

Let’s test this pattern by creating a client program

  1. package com.kb.state;
  2.  
  3. public class Refrigerator {
  4.    
  5.     public static void main(String[] args) {
  6.         DeviceContext context = new DeviceContext();
  7.         State refrigeratorOnState = new DeviceOnState();
  8.         State refrigeratorOffState = new DeviceOffState();
  9.        
  10.         context.setState(refrigeratorOnState);
  11.         context.execute();
  12.        
  13.         context.setState(refrigeratorOffState);
  14.         context.execute();
  15.        
  16.     }
  17.  
  18. }
package com.kb.state;

public class Refrigerator {
	
	public static void main(String[] args) {
		DeviceContext context = new DeviceContext();
		State refrigeratorOnState = new DeviceOnState();
		State refrigeratorOffState = new DeviceOffState();
		
		context.setState(refrigeratorOnState);
		context.execute();
		
		context.setState(refrigeratorOffState);
		context.execute();
		
	}

}



We can see that using State pattern we got the same output without writing any if-else blocks

Now its not tightly coupled with if-else blocks

If we want to add any new state, we can easily add it without worrying about if-else blocks

Consider an example that, we need to add new state for the device called “Installing” state

Now we just need to create this state concrete class and use it in client program

Let’s see how can we do it

Step 1

Create a new state class for Installing state

  1. package com.kb.state;
  2.  
  3. public class DeviceInstallingState  implements State {
  4.  
  5.     @Override
  6.     public void execute() {
  7.         System.out.println("Device is Installing , Please do not turnOff");
  8.     }
  9.  
  10. }
package com.kb.state;

public class DeviceInstallingState  implements State {

	@Override
	public void execute() {
		System.out.println("Device is Installing , Please do not turnOff");
	}

}

Step 2

Use the same in the client program as below

  1. State refrigeratorInstallState = new DeviceInstallingState();
  2.         context.setState(refrigeratorInstallState);
  3.         context.execute();
State refrigeratorInstallState = new DeviceInstallingState();
		context.setState(refrigeratorInstallState);
		context.execute();


We are just creating an instance of new state and attaching it to context class.

Whole client class with previous states is as below

  1. package com.kb.state;
  2.  
  3. public class Refrigerator {
  4.    
  5.     public static void main(String[] args) {
  6.         DeviceContext context = new DeviceContext();
  7.         State refrigeratorOnState = new DeviceOnState();
  8.         State refrigeratorOffState = new DeviceOffState();
  9.        
  10.         context.setState(refrigeratorOnState);
  11.         context.execute();
  12.        
  13.         context.setState(refrigeratorOffState);
  14.         context.execute();
  15.        
  16.         State refrigeratorInstallState = new DeviceInstallingState();
  17.         context.setState(refrigeratorInstallState);
  18.         context.execute();
  19.        
  20.     }
  21.  
  22. }
package com.kb.state;

public class Refrigerator {
	
	public static void main(String[] args) {
		DeviceContext context = new DeviceContext();
		State refrigeratorOnState = new DeviceOnState();
		State refrigeratorOffState = new DeviceOffState();
		
		context.setState(refrigeratorOnState);
		context.execute();
		
		context.setState(refrigeratorOffState);
		context.execute();
		
		State refrigeratorInstallState = new DeviceInstallingState();
		context.setState(refrigeratorInstallState);
		context.execute();
		
	}

}




Advantages of State pattern


Whenever we need to add new state for additional behaviour, its very easy to achieve.

Helps to avoid if-else (or) switch conditions in the program to execute different behaviours

Code is more robust and easy to maintain

When to use this pattern?

We should use this pattern whenever the change in the state of an object changes its behaviour.

About the Author

Karibasappa G C (KB)
Founder of javainsimpleway.com
I love Java and open source technologies and very much passionate about software development.
I like to share my knowledge with others especially on technology 🙂
I have given all the examples as simple as possible to understand for the beginners.
All the code posted on my blog is developed,compiled and tested in my development environment.
If you find any mistakes or bugs, Please drop an email to kb.knowledge.sharing@gmail.com

Connect with me on Facebook for more updates

Share this article on