Design Patterns – State

State is a behaviour pattern. We need to look this pattern when:

We have a object that changes its behaviour when its internal state changes. The behaviour changes as if the object changed its class.

Structure

  1. Context: it’s the object that changes its behaviour when changes its internal state.
    • state: is a private IState (State Interface) variable
    • The context expose a setter for passing it a new state object – changeState().
  2. State interface declares the state-specfic methods and must be implement for all concrete State classes.
  3. Concrete State classes: They are each specific state.
    • Must be implement IState Interface
    • Can inherit from a abstract class that encapsulate some common behaviour to avoid code duplication –> Only if I need it –> Not mandatory.
    • Have got a context reference because through that the state can fetch any required data from the context, as well as set the new state (state transition)

Example: Work Item Tracking System

We will build a Work Item Tracking System. For us, the work items have four internal states:

  1. Proposed
  2. Active
  3. Resolved
  4. Closed

The order is mandatory and must be respected.
We can use seven commands in the UI for interact with them:

  1. Create: Generate a new work item with state: Proposed
  2. Edit: Modify title and description of the work item
  3. Open: Change State to Active
  4. Resolve: Change State to Resolved
  5. Verify: Change State to Closed
  6. Print: Show work item data
  7. Delete: Remove a work item from storage
Asociation between Commands and states & Worflows

Bad way – Simple system!

Ok, when we start to code the system maybe we need code fast with the promise: “I will make a refactoring tomorrow!”.
Maybe you are able code something like that:

  • Console app
  • Work Item Entity with property and business methods
  • WorkItem Service to interact with the storage
  • A enum for states

Class Diagram:

This approach have a big problem: basically a lot of switch statements.

public void Open() //Try to change current state to Active
{
    switch (State) //Current State
    {
        case eState.Proposed:
            ChangeState(eState.Active);
            Console.WriteLine("Work Item State has changed to Active");
            break;
        case eState.Active:
            Console.WriteLine("Work Item is already Active");
            break;
        case eState.Resolved:
            Console.WriteLine("You can't Open a Resolved Work Item");
            break;
        case eState.Closed:
            Console.WriteLine("Work Item is closed and can not be modified");
            break;
        default:
            break;
    }
}
public void Verify()//Try to change current state to Closed
{
    switch (State) //Current State
    {
        case eState.Proposed:
            Console.WriteLine("You can't Close a Proposed Work Item");
            break;
        case eState.Active:
            Console.WriteLine("You can't Close a Active Work Item");
            break;
        case eState.Resolved:
            ChangeState(eState.Closed);
            Console.WriteLine("Work Item State has changed to Closed");
            break;
        case eState.Closed:
            Console.WriteLine("Work Item is already Closed");
            break;
        default:
            break;
    }
}

yeahh, a lots of switch statements. When we execute a operation that tries to change the internal state with this approuch we need to check the current internal state and then, apply business rule.
You just imagine if we have a lot of states and operations, bigger switches!

Good way – Use State Pattern!

Well, we use the State Pattern to resolve this problem. First, we need to ask us : Which are the states ?
In this case is easy, the states are:

  1. Proposed
  2. Active
  3. Resolved
  4. Closed

Why are “the states”? Because when a workitem change its state, reacts differently to the commands. With the last sentence I try to say for example:

When a Work Item is Proposed, you can DELETE it but if the WorkItem is Active you can’t delete it. In conclusion, for each COMMAND the work item changes its behaviour and has different business rules.

In our example the work item changes its behaviour when the following commands:

  • Open
  • Resolve
  • Verify
  • Delete
  • Print –> This is a new business Rule when we print the WorkItem data each State writes it in different colors.

Excellent, in resume: we have States, Commands and WorkItems. When we send Commands to the workitems, they apply different business rules and finally, change their behaviour.

Class Diagram with State pattern

We implement the pattern, we can note:

  1. We create ICommand Interface, this interface is the State Interface. In other words, these commands do that the Work Item changes its behaviour. The commands Delete, Open, Print, Resolve & Verify depend exclusively of the current State –> for each state we need to apply different business rules. We add a extra methods:
    • SetContext(context): In our case, we don’t use this method instead we use a Constructor overload to set the context, for example: public Active(WorkItem context). this constructor reeplaces the method: SetContext (InitialState) used in the classic pattern.
  2. We create a class for each State (Concrete classes): Proposed, Active, Resolved and Closed. These classes implement the Interface ICommand. In other words, it’s concern of each State knows how anwsers to a specific command.
  3. Work Item class (CONTEXT) has two extra methods
    • ChangeState(state): this method allows to change the internal state, how the work item is passed like a parameter to the State Classes, each state class can change the internal state of the work item (the Context)
    • Constructor for setting the initial State: this constructor replaces the method: Context(InitialState) in the classic pattern.

Work Item Class (CONTEXT)

The work Item has ICommand Interface (represent the internal State) – _StateCommand field.
WorkItem() Constructor set the Initial Internal State.
ChangeState() method allows set another state.
Furthemore, you can look to the Proposed Class receives the workitem like a parameter.

ICommand Interface (State Interface)

The Icommand Interface has all Commands that depend on Internal State. All commands change their behaviour depending on the CURRENT INTERNAL STATE.

State Class (Concrete State class)

For example this is the Active class:

public class Active : BaseState, ICommand
{
    private WorkItem _context;

    public Active(WorkItem context)
    {
        _context = context;
    }

    public bool Delete()
    {
        return false;
    }


    public void Open()
    {
        Console.WriteLine("Work Item is already Active");
    }

    public void Print()
    {
        Console.ForegroundColor = ConsoleColor.Blue;
        Print(_context);
        Console.ForegroundColor = ConsoleColor.White;
    }

    public void Resolve()
    {
        _context.ChangeState(new Resolved(_context));
        Console.WriteLine("Work Item State has changed to Resolved");
    }

    public void SetContext(WorkItem workItem)
    {
        _context = workItem;
    }

    public void Verify()
    {
        Console.WriteLine("You can't Close a Active Work Item");
    }
}

You can see how each method has a specific behaviour for this STATE.
Furthemore, you should put special attention to the method:

public void Resolve()
{
    _context.ChangeState(new Resolved(_context));
    Console.WriteLine("Work Item State has changed to Resolved");
}

In this method, you can see a STATE TRANSITION because when a Active workItem receive the command Resolve: This operation is allowed! Then, The work item changes its state to Resolved!

Base state class

public abstract class BaseState
{
    public virtual void Print(WorkItem workItem)
    {
        Console.WriteLine("WorkItem: ");
        Console.WriteLine($"Title: { workItem.Title } ");
        Console.WriteLine($"Description: { workItem.Description}");
        Console.WriteLine($"State: { workItem.GetDescriptionState() }");
    }
}

For our example, we use a simple base to show how encapsulate common behaviour in this pattern.

Work Item class & Operations with statePattern

When the work item invokes any command method only call to _StateCommand and that’s all!

A bit complex but very scalable & maintainable!

All code in my Github:
https://github.com/morales-franco/DesignPatterns