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

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

Comment (12)

  1. Hi KB,

    I have one question related to Singleton Design pattern for multi threading.

    public static LazySingletonDoubleLockCheck getInstance(){
    if(singletonInstance==null){
    synchronized (LazySingleton.class) {
    if(singletonInstance ==null){
    singletonInstance = new LazySingletonDoubleLockCheck();
    }
    }
    }
    return singletonInstance;
    }
    }

    Cann’t we make the whole method as synchronized (public static synchronized LazySingletonDoubleLockCheck getInstance()) ?.
    please correct me if my understanding is wrong

  2. Hi KB,
    Change the commented line number 26 at SerializeAndDeserializeTest.java in Approach 4 that is // Serialize to a file to Deserialize to a file just to avoid confusion especially for the beginners.

    Consider it as a minor suggestion.

  3. Hello

    I really liked your blog.however in this post i would like to add something ,

    you have mentioned there that

    *How we create object in Java ?

    Yes using constructor , and we should not allow users to access constructor and execute it every time they try to. *

    I believe this statement is completely wrong. constructor is executed that does not mean object is created. object is create only using new operator and constructor is executed to initialize the instance variable.

    Kindly correct it.. πŸ™‚

    thanks again.

    1. Karibasappa G C (KB)

      Thanks PushP for bringing this into discussion!!

      Let me try to make you understand the below line
      we should not allow users to access constructor and execute it every time they try to.

      If we are making someone to access constructor I mean execute constructor multiple times it just creates new object according to Java concept.

      How ?
      you know that constructors don’t have names right,so the only we to make the constructor execution is by creating an object using new.
      I agree that constructor execution and object creation are different activities but my point here is when you allow someone to execute the constructor multiple times, it means you are calling constructors multiple times because there is no other way to execute the constructors.
      Note:going through programmatically not through reflection and all.

      your opinion
      constructor is executed that does not mean object is created , object is created only using new operator and constructor is executed to initialize the instance variable

      my understanding on your opinion
      if I go by English i agree with this sentence , but going by Java concept i can not agree with this.
      Because when constructor is executed it means that you have called it using new class_name(), it means one object gets created in Java.
      I am not saying constructor execution and object creation are synonyms but what i am saying is they are mutually dependent.

      So my point here is simple,
      we should not allow users create object multiple times which is same as we should not allow users to execute the constructors multiple times.

      preventing constructor execution is same as not allowing someone to create an object.

      Happy to hear your inputs again and Thank you so much !!

  4. Hi Mani,,,

    I have added subscribe option on the right sidebar, you can subscribe there to receive the updates πŸ™‚

    Thank you once again…and welcome for your comments always.

  5. Hi Mani, Its really very good notice…

    I forgot to add clone and also i didn’t add one more approach using ENUM.

    But Reflection you are right , i didnt notice this situation. but its good to cover that as well.

    so i will edit this post sometime to include all the above scenarios.

    Thanks a lot for reading , observing the things and suggesting.

    Keep Suggesting the posts during your free time πŸ™‚ Thank you once again…

  6. Manikandan Jayaraman

    Good one, KB πŸ™‚

    I can break your code using reflection though:
    ===
    // Access constructor using reflection
    Class clazz = FinalSingleton.class;
    Constructor cons = clazz.getDeclaredConstructor();
    cons.setAccessible(true);
    FinalSingleton instanceThree = cons.newInstance();
    instanceThree.setX(300);
    System.out.println(“instanceThree.getX() :: “+instanceThree.getX());
    ===

    the above creates a new instance.you can avoid that by changig your constructor
    ===
    private FinalSingleton() {

    //If-block needed to avoid creation of another object using reflection
    /*if (LazyLoadFinalSingleton.SINGLETONINSTANCE != null) {
    throw new IllegalStateException(“Inside FinalSingleton(): instance already created.”);
    }*/

    x = 100;
    System.out.println(“Constructor Called. Instance created.”);
    }
    ===

    Also good to override clone method and throw clone not supported exception. You will never know where the loop hole is. πŸ™‚

Leave a Comment

  • You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code lang=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" extra="">

    • Please answer this simple challenge to post your valuable comment *