Behavioral Pattern, allowing an object to switch its behaviour, when its internal state changes. It looks more like an object switching its class.

Problem
It took a long time until I came up with an idea how to illustrate State Design Pattern. Let’s imagine an ATM – thing which successfully is being taken out from streets since last years – it has few functions:
- insert card
- enter PIN code
- withdraw cash
- eject card
Depending on which stage (state) of withdrawing cash we are, there are different states of ATM:
- No card inserted
- card inserted
- PIN code (in)correct
- out of money
Imagine now a situation, where user would like to withdraw cash, but despite of inserting card and entering correct PIN code, the ATM has no cash to withdraw. If these cases where considered in a huge class with four functionalities, we would somehow hold an information if the card is inserted, PIN code is correct, the cash is available, or even if the card is inaccessible. Later depending on every functionality, we would have to check every ATM’s state to allow or lock given functionality. That logic would lead to one thing – creating a code, which has lots of if statements, which would be very painful to read, and hard to maintain aswell.
State Solution
For help comes State Design Pattern – we will separate four different classes for every state which will have their own implementations for given method. It means, that instead having one class and holding information about specific ATM’s state, we are going to create four implementations of ATM’s behaviour for each state it currently is in.

UML diagram above shows base abstract class with four methods, with four classes which are representing ATM’s state. Every state is containing a reference to Context – an object which will be some sort of ATM’s state medium, which is gonna manage them -> for example, if we have an ATM without card, and user inserts the card, we have to pass from OutOfCard state, to InsertedCard state. To integrate them we have context, which is gonna hold current ATM’s state, and change it basing on taken actions. What is worth saying is fact, that the reference between State and Context is mutual to induce state change if necessary.
public abstract class State
{
protected Context _context;
protected State(Context context)
{
_context = context;
}
public abstract void insertCard();
public abstract void ejectCard();
public abstract void insertPIN(int pin);
public abstract void withdrawCash(int amount);
}
public class InsertedCard: State
{
public InsertedCard(Context context) : base(context)
{
}
public override void ejectCard()
{
Console.WriteLine("Card has been ejected");
_context.changeState(new OutOfCard(_context));
}
public override void insertCard()
{
Console.WriteLine("Card inserted already");
}
public override void insertPIN(int pin)
{
if (pin == 1234)
{
Console.WriteLine("Pin correct");
_context.changeState(new InsertedPIN(_context));
}
else
{
Console.WriteLine("Incorrect PIN");
Console.WriteLine("Card ejected");
_context.changeState(new OutOfCard(_context));
}
}
public override void withdrawCash(int amount)
{
Console.WriteLine("Insert PIN first");
}
}
public class OutOfCard: State
{
public OutOfCard(Context context) : base(context)
{
}
public override void ejectCard()
{
Console.WriteLine("No card inserted yet");
}
public override void insertCard()
{
Console.WriteLine("Card inserted");
_context.changeState(new InsertedCard(_context));
}
public override void insertPIN(int pin)
{
Console.WriteLine("no card inserted yet");
}
public override void withdrawCash(int amount)
{
Console.WriteLine("no card inserted yet");
}
}
internal class OutOfCash: State
{
public OutOfCash(Context context) : base(context)
{
}
public override void ejectCard()
{
Console.WriteLine("No cash");
}
public override void insertCard()
{
Console.WriteLine("No cash");
}
public override void insertPIN(int pin)
{
Console.WriteLine("No cash");
}
public override void withdrawCash(int amount)
{
Console.WriteLine("No cash");
}
}
public class InsertedPIN: State
{
public InsertedPIN(Context context) : base(context)
{
}
public override void ejectCard()
{
Console.WriteLine("Card has been ejected");
_context.changeState(new OutOfCard(_context));
}
public override void insertCard()
{
Console.WriteLine("Card inserted already");
}
public override void insertPIN(int pin)
{
Console.WriteLine("Correct PIN code inserted");
}
public override void withdrawCash(int amount)
{
if(amount > _context.AvailableCash)
{
Console.WriteLine("That amount of cash is not available");
}
else
{
Console.WriteLine($"You have withdrawn {amount} from the mashine");
_context.AvailableCash -= amount;
if(_context.AvailableCash == 0)
{
_context.changeState(new OutOfCard(_context));
}
else
{
Console.WriteLine("Card ejected");
_context.changeState(new OutOfCard(_context));
}
}
}
}
public class Context
{
private State _currentState;
public int AvailableCash { get; set; } = 2000;
public void changeState(State newState)
{
_currentState = newState;
}
public Context()
{
_currentState = new NoCard(this);
}
public void insertCard()
{
_currentState.insertCard();
}
public void ejectCard()
{
_currentState.ejectCard();
}
public void insertPIN(int pin)
{
_currentState.insertPIN(pin);
}
public void withdrawCash(int amount)
{
_currentState.withdrawCash(amount);
}
}
Foregoing code is long, but beautifully gives back how every possible class works while being under different condition. Instead of using neverending if statements, we have taken an advantage of State Design Pattern, which in the end resulted in much less messy code.