In this article we are going to learn about State Design Pattern.

  • What is State pattern?
  • What are the basic principles?
  • How to implement?
  • where we can use this?

I have used Java with Eclipse and C# with VS2010.

What is State Pattern?

In OO design, when we need to change behavior of an object depending on its state, we use State pattern.

Lets think about payment transaction domain. The main object responsible for a payment transaction used to notify a set a set of other objects depend on his state. Suppose, there is a successful transaction, it will notify customer, balance object. If, there were communication problem, it will notify client, then notify bank manager type objects or it there is any insecure activity then it also notify bank’s security notifying object.

State pattern allows an object to change its behavior depend on the internal state change.

So, now, what is state. A state of an object refers to a.values of its properties b.effects of functions(may be void or any valuated output). So, if the state change, it will work differently.

Let’s consider a sales order , a sales order can be new order, registered in system, granted order, shipped order, invoicing or even cancelled. These are the state of the same order state and its inner states will be change along with the functionality of the whole sales order object.

Typically in state design pattern contains

  • Context :Context is the main object. It is the container of different states.
  • States : It should be derived among same grouped classes

Principles :

  • Allowing changing behavior
  • Let an object decide it behavior based on its state

UML :

uml-state

How to implement?

As we know, we will have context , states and client who actually calls the context. So, lets think about how to implement. It is for sure, a context will contain all of its state.

And, a context will have the functions which will be changed as soon as its state has been changed. So, we can understand this context is actually a composition of all state.

And, an individual state should have function defining for each variety of state. That means either a method taking parameter to vary from state to state or, methods for each state behavior.

These are the simple ideas, let see more detail with example.

Example :

Let’s consider an android mobile connecting to PC. We will represent an Android mobile as Context object(we may apply interface also that will be called from client).

We have mainly three states( three way to connect a device to PC)

  • Connect to PC for charge only : An android device will be connected. Device will be charging only in this state.
  • Connect to PC with ADB Enabled : An android device can be connected to PC with debug mode. In this mode ADB(Android Debug Bridge) will be activated and we can control the android mobile from PC
  • Connect to PC with USB Storage Enabled : An Android device can be connected to PC with USB storage mode. We can see the mobile’s storage as drive in this mode.

And, every time the android mobile is connected , depending on state its behavior will be changed. So, that means , each state will represent different behavior.

That means, we have to define at least one method to represent the function of a particular behavior.

We may use more than one method or even describe in a single method, but I guess it is better to use separate methods to represent separate state behaviors(easy to understand).

And, as I told in the beginning, Android will be our context. We may use a context Interface IMobile which should be implemented by the context object Android so that client can initiate Android using IMobile.

This context will have facility to change its own state and providing method to access its state.

And, lastly a Client. A client calls the context and may change behavior to get the context see functions are changing. So,

Step 1 :Defining States :

So, Start with IState interface that contains all state related changing method.

    public interface IState {    
        public void charge();
        public void usbMount();
        public void adbConnect();
    }

Note: We could make a common method and use parameter to define functionality. But, I use separate methods to understand properly as well as I have use those methods in side separate states to change the states.

And, implementing states ChargingState, AdbState ,USBMountingState

    public class ChargingState implements IState{
        private IMobile myMobile;
        public ChargingState(IMobile aMobile){
            myMobile = aMobile;
        }
        public void charge() {
            System.out.println("Mobile is connected to PC for charging only");
        }
        public void usbMount() {
           System.out.println("While Charging Only mode device can not mount as USB storage, please select USB mount from Device");
           myMobile.setMobileState(myMobile.getUsb());
       }
       public void adbConnect() {
           System.out.println("While Charging Only mode we can not access ADB , please select Android Debugging from Device settings");
           myMobile.setMobileState(myMobile.getAdb());
       }
   } 

    public class AdbState implements IState{
        private IMobile myMobile;
        public AdbState(IMobile aMobile){
            myMobile = aMobile;
        }
        public void charge() {
            System.out.println("While ADB mode, your device is by default charging");
            myMobile.setMobileState(myMobile.getCharging());
        }
       public void usbMount() {
           System.out.println("While ADB mode , device can not mount as USB storage, please select USB mount from Device");
           myMobile.setMobileState(myMobile.getUsb());
       }
       public void adbConnect() {
           System.out.println("Your device is connected in Android Debugging Mode, to cancel ADB mode please dis-select Android Debugging from Device settings");
       }
   }

    public class USBMountingState implements IState{
        private IMobile myMobile;
        public USBMountingState(IMobile aMobile){
            myMobile = aMobile;
        }
        public void charge() {
            System.out.println("While USB Only mode, your device is by default charging");
            myMobile.setMobileState(myMobile.getCharging());
        }
       public void usbMount() {
           System.out.println("Deviec is in USB mode, access mobile storage from file explorer");
       }
       public void adbConnect() {
           System.out.println("While USB Only mode we can not access ADB , please select Android Debugging from Device settings");
           myMobile.setMobileState(myMobile.getAdb());
       }
   }

Step 2 : Creating Context :

Now, Lets make a context interface IMobile that will contain all state changing behavior as well as behavior calling functions.

    //Context Interface
    public interface IMobile {
        public void setMobileState(IState aState);
        public void ChargeMobile();
        public void USBConnect();
        public void AdbAccess();
        public IState getCharging() ;
        public IState getUsb() ;
        public IState getAdb() ;
   }

And, implementing class Android

    //Context Class
    public class Android implements IMobile{
        private IState charging;
        private IState usb;
        private IState adb;
        
        private IState mobileState;    
        public void setMobileState(IState aState) {
            mobileState= aState;
       }
       public Android(){
           charging = new ChargingState(this);
           usb = new USBMountingState(this);
           adb = new AdbState(this);
           mobileState = charging;
       }
       //next three are for accessing functions in one state
       public void ChargeMobile(){
           mobileState.charge();
       }
       public void USBConnect(){
           mobileState.usbMount();
       }
       public void  AdbAccess() {
           mobileState.adbConnect();
       }
       // next three are getting states
       public IState getCharging() {
           return charging;
       }    
       public IState getUsb() {
           return usb;
       }    
       public IState getAdb() {
           return adb;
       }
   }

Step 3 : Calling From Client :

So, now we call context from client and we will see when the context changed, the same method of a same context provides different results.

    public class Program {
        public static void main(String[] args) {
            IMobile samsungGalaxy = new Android();//initial state will be charging 
            samsungGalaxy.ChargeMobile();
            samsungGalaxy.AdbAccess();//mode will be change to ADB
            samsungGalaxy.AdbAccess();
            samsungGalaxy.USBConnect();//mode will change to USB
            samsungGalaxy.USBConnect();
        }
   }

Sources

Usages :

  1. When we need an individual object’s behavior specified by its state.(not decided by other objects)
  2. When are design stand alone system object( like as device representing objects).
  3. Very good to represent a data table or database state or record state with this pattern.

And sometimes it is handy to use with other patterns.