Software

State Pattern

The State pattern is primarily used when you need to change the behavior on an object based upon the state that it’s in t run-time. For example vending machine has a different sates and can do specific actions based on those states.

State Pattern State Diagram.png

Code example:

public class VendingMachine {

    public VendingMachine(int count) {
        ...
    }

    //Handle User Events
    public void InsertDollar(){
        ...
    }

    public void EjectMoney(){
        ...
    }

    public void Dispense(){
        ...
    }
}

Custom Implementation:

State:

sealed class State { //Singleton objects for states
    private State();

    //all potential vending machine states as singletons
    public sealed static State Idle = new State();
    public sealed static State HasOneDollar = new State();
    public sealed static State OutOfStock = new State();
}

Vending Machine:

public class VendingMachine {
    private State currentState;
    private int count;

    public VendingMachine(int count) {
        if {count > 0){
            currentState = State.Idle;
            this.count = count;
        }
        else {
            currentState = State.OutOfStock;
            this.count = 0;
        }
    }
}

Insert Dollar trigger:

public void InsertDollar() {
    if (currentState == State.Idle) {
        currentState = State.HasOneDollar;
    }
    else if (currentState == State.HasOneDollar) {
        doReturnMoney();
        currentState = State.Idle;
    }
    else if (currentState == State.OutOfStock) {
        doReturnMoney();
    }
}

The proper implementation:

This code looks massive, but how it should look better with the proper implementation of the State Design pattern? Firstly, we have to define a state interface with a method for each trigger that a state needs to respond to.

State (Vending Machine) Class Diagram.png
public interface State {
    public void InsertDollar(VendingMachine vendingMachine);
    public void EdjectMoney(VendingMachine vendingMachine);
    public void Dispense(VendingMachine vendingMachine);
}

Now we have to implement each state, for example Idle State will look like this:

public class IdleState: IState {
    public void InsertDollar(VendingMachine vendingMachine){
        Console.WriteLine("Dollar inserted");
 
        vendingMachine.SetState(vendingMachine.GetHasOneDollarState());
    }

    public void EjectMoney(VendingMachine vendingMachine) {
        Console.WriteLine("No money to return");
    }

    public void Dispense(VendingMachine vendingMachine) {
        Console.WriteLine("Payment required");
    }
}
public class HasOneDollarState: IState {
    public void InsertDollar(VendingMachine vendingMachine){
        Console.WriteLine("Already have one dollar");
 
        vendingMachine.DoReturnMoney();
        vendingMachine.SetState(vendingMachine.GetIdleState());
    }

    public void EjectMoney(VendingMachine vendingMachine) {
        Console.WriteLine("Returning Money");

        vendingMachine.DoReturnMoney();
        vendingMachine.SetState(vendingMachine.GetIdleState());
    }

    public void Dispense(VendingMachine vendingMachine) {
        Console.WriteLine("Releasing product");

        if (vendingMachine.GetCount() > 1) {
            vendingMachine.DoReleaseProduct();
            vendingMachine.SetState(vendingMachine.GetIdleState());
        }
        else {
            vendingMachine.DoReleaseProduct();
            vendingMachine.SetState(vendingMachine.GetOutOfStockState());
        }
    }
}
public class VendingMachine {
    private State idleState;
    private State hasOneDollarState;
    private State outOfStockState;

    private State currentState;
    private int count;

    public VendingMachine(int count){
        // make the needed states
        idleState = new IdleState();
        hasOneDollarState = new HasOneDollarState();
        outOfStockState = new OutOfStockState();

        if(count > 0) {
             currentState = idleState;
             this.count = count;
        }
        else {
            currentState = outOfStockState;
            this.count = 0;
        }
    }

    //Delegates to states
    public void InsertDollar(){
        currentState.InsertDollar(this);
    }

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

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

The structure of the State pattern:

State Pattern Class Diagram.png

One thought on “State Pattern

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.