State Design Pattern in C# with Example

1. Definition

The State Design Pattern allows an object to change its behavior when its internal state changes. This pattern treats the state as a full-blown object with its own logic and transition rules, ensuring that state-specific code is separated and organized.

2. Problem Statement

Consider an application where an object needs to change its behavior based on its internal state. Implementing state transitions and behaviors directly within the object can lead to a class that's hard to maintain, with numerous conditional statements and intertwined logic.

3. Solution

The State pattern suggests representing different states as separate classes, with a common interface for all state-specific behaviors. The context object then maintains a reference to one of these state objects, representing its current state, and delegates state-specific tasks to it.

4. Real-World Use Cases

1. A traffic light system where lights switch between red, yellow, and green states.

2. Different modes in a video game, such as pausing, playing, and game-over states.

3. A document system where documents can be in draft, published, or archived states.

5. Implementation Steps

1. Define a common interface for all states.

2. Implement concrete state classes for each specific state.

3. The context class changes its state by switching the state object it's delegating to.

6. Implementation in C#

// State interface
public interface IState
{
    void Handle(Context context);
}

public class ConcreteStateA : IState
{
    public void Handle(Context context)
    {
        Console.WriteLine("Handling state A");
        context.SetState(new ConcreteStateB());
    }
}

public class ConcreteStateB : IState
{
    public void Handle(Context context)
    {
        Console.WriteLine("Handling state B");
        context.SetState(new ConcreteStateA());
    }
}

public class Context
{
    private IState _state;

    public Context(IState initialState)
    {
        _state = initialState;
    }

    public void SetState(IState state)
    {
        _state = state;
    }

    public void Request()
    {
        _state.Handle(this);
    }
}

public class Program
{
    public static void Main()
    {
        Context context = new Context(new ConcreteStateA());

        // Simulate state changes
        context.Request();
        context.Request();
    }
}

Output:

Handling state A
Handling state B

Explanation:

In this example, the Context class delegates its behavior to different state objects (ConcreteStateA and ConcreteStateB). 

When a Request is called on the context, it delegates the handling to its current state, which then changes the state of the context.

7. When to use?

1. Use the State pattern when an object's behavior should change based on its state, and complex state transition logic can be isolated from the object's main logic.

2. When an object needs to switch between multiple modes of operations.


Comments