Design Pattern in Java - Part 2, State Design Pattern

Anshul KumarAnshul Kumar
3 min read

Table of contents

It is one of the behavioral design pattern. This pattern can be used when we have different state of an object. With the help of this pattern we can decide the action of object in a particular state. We can decide the object's behaviour and block the unwanted action of object.

We can achieve same functionality without state pattern. For that we have to use if else in every state action code to check what is the current state and what are the action we can take in this state. It will make code complex and hard to read.

In future if we get more state then we need to change the code every-time. It will be a violation of Open-Closed Principle.

If we take the TV remote example then without using the pattern code will be look like below.

TVRemote.java

public class TVRemote {
    private String currentState = "Off";

    public void switchOnTV() {
        if(currentState.equalsIgnoreCase("off")){
            System.out.println("Turning on the TV");
        } else if(currentState.equalsIgnoreCase("on")) {
            System.out.println("No action needed");
        }
    }

    public void switchOffTV() {
        if(currentState.equalsIgnoreCase("On")){
            System.out.println("Turning off the TV");
        } else if(currentState.equalsIgnoreCase("off")) {
            System.out.println("No action needed");
        }
    }

    public void changeChannel() {
        if(currentState.equalsIgnoreCase("On")){
            System.out.println("changing the channel");
        } else if(currentState.equalsIgnoreCase("off")) {
            System.out.println("No action needed");
        }
    }
}

You can see this in the above code. There are already a lot of conditions in small code. It has a tight coupling between implementation and the client code will be very hard to maintain and extend.

Now let's try the state pattern. With the state pattern, the class diagram will look like below.

state-design-pattern-2.png

In the above diagram, state implementation is independent of each other and we can extend easily if we have more states in future.

Here is the code of implementation

State.java

public interface State {
    public void action();
}

TurnOnTv.java

public class TurnOnTv implements State {

    @Override
    public void action() {
        System.out.println("Turning on Tv");
    }
}

TurnOffTv.java

public class TurnOffTv implements State {

    @Override
    public void action() {
        System.out.println("Turning off Tv");
    }
}

ChangeChannel.java

public class ChangeChannel implements State {

    @Override
    public void action() {
        System.out.println("Changing channel");
    }
}

TVRemoteContext.java (it will keep the current state)

public class TVRemoteContext implements State {

    private State state;

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

    public State getState() {
        return this.state;
    }

    @Override
    public void action() {
        this.state.action();
    }
}

TVRemote.java

public class TVRemote {
    public static void main(String[] args) {
        TVRemoteContext context = new TVRemoteContext();
        State turnOnTv = new TurnOnTv();
        State turnOffTv = new TurnOffTv();
        State changeChannel = new ChangeChannel();

        context.setState(turnOnTv);
        context.action();

        context.setState(turnOffTv);
        context.action();

        context.setState(changeChannel);
        context.action();
    }
}

It looks clean and extendable easily. We can enhance the above code according to requirements. Hope it helps you. Happy reading :)

I explained the strategy pattern in my previous blog checkout https://anshul007.hashnode.dev/design-pattern-in-java-part-1-strategy-design-pattern

0
Subscribe to my newsletter

Read articles from Anshul Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Anshul Kumar
Anshul Kumar