State Programming Pattern

Introduction

State programming pattern allow the object for changing its behavior without changing its class.  Also, by implementing it, the code should remain cleaner without many if/else statements. The whole idea of this pattern is based on Finite State Machine

Definition

State is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.

Problem solved by „State”

A monolithic object’s behavior is a function of its state, and it must change its behavior at run-time depending on that state. Or, an application is characterized by large and numerous case statements that vector flow of control based on the state of the application.

In this example we will consider a fan control.

class Fan {
    private int currentState;

    public Fan() {
        currentState = 0;
    }

    public void pull() {
        if (currentState == 0) {
            currentState = 1;
            System.out.println("low speed");
        } else if (currentState == 1) {
            currentState = 2;
            System.out.println("medium speed");
        } else if (currentState == 2) {
            currentState = 3;
            System.out.println("high speed");
        } else {
            currentState = 0;
            System.out.println("turning off");
        }
    }
}

Let’s test our fan.

public class CoolingSystem {
    public static void main(String[] args) {
        Fan fan = new Fan();
        fan.pull(); // set low speed
        fan.pull(); // set medium speed
        fan.pull(); // set high speed
        fan.pull(); // turn off
        fan.pull(); // set low speed
    }
}

Solution

Let’s start implementing State Pattern with creating interface for state. It should contain a method, which will set a fan to particular speed in the classes which will implement this interface. This metod should take Fan object as argument, due to that we need easy way for chaning state and Fan class will have a function for that.

interface State {
    void pull(Fan wrapper);
}

In next step let’s prepare state classes like on below diagram.

Notice that every state do have information about next state.

class Off implements State {

    public Off(){
        System.out.println("Turning off");
    }

    public void pull(Fan wrapper) {
        System.out.println("Preparation to move from Off State to Low State");
        wrapper.setState(new Low());
    }
}
class Low implements State {

    public Low(){
        System.out.println("Low speed");
    }

    public void pull(Fan wrapper) {
        System.out.println("Preparation to move from Low State to Medium State");
        wrapper.setState(new Medium());
    }
}
class Medium implements State {

    public Medium(){
        System.out.println("Medium speed");
    }

    public void pull(Fan wrapper) {
        System.out.println("Preparation to move from Medium State to High State");
        wrapper.setState(new High());
    }
}
class High implements State {

    public High(){
        System.out.println("High speed");
    }

    public void pull(Fan wrapper) {
        System.out.println("Preparation to move from High State to Off State");
        wrapper.setState(new Off());
    }
}

Last step is adjusting Fan class. It is important to implement function for changing state here.

class Fan {
    private State currentState;

    public Fan() {
        currentState = new Off();
    }

    public void setState(State s) {
        currentState = s;
    }

    public void pull() {
        currentState.pull(this);
    }
}

Pros

  • Single Responsibility Principle. Organize the code related to particular states into separate classes.
  • Open/Closed Principle. Introduce new states without changing existing state classes or the context.
  • Simplify the code of the context by eliminating bulky state machine conditionals.

Cons

  • Applying the pattern can be overkill if a state machine has only a few states or rarely changes.
Posted in Programming patternsTags:
Write a comment