State Pattern in C#: Definition, Examples, Pros, Cons, and Use Cases

State Pattern in C#: Definition, Examples, Pros, Cons, and Use Cases

The State pattern in C# is a behavioral design pattern that allows an object to change its behavior dynamically when its internal state changes.

The State pattern encapsulates different behaviors into separate state classes and delegates behavior execution to the current state object. Instead of using large conditional statements, the object changes its behavior by switching between state objects. Each state class represents a specific state and defines behavior appropriate for that state. The context object maintains a reference to the current state and forwards requests to it. In C#, the State pattern is commonly used in workflow systems, game development, UI controls, media players, and finite state machines.

Why We Use State Pattern in C#?

We use the State pattern in C# to:

• Eliminate large if-else or switch statements
• Manage complex state-dependent behavior
• Improve maintainability
• Encapsulate state-specific logic
• Support dynamic behavior changes
• Simplify workflow management
• Follow the Open/Closed Principle
• Improve readability in state-driven systems

When Should We Use State Pattern in C#?

The State pattern should be used when:

• Object behavior changes based on internal state
• Applications contain many state-based conditions
• State transitions are frequent
• Workflow systems require clear state management
• Finite state machine behavior is needed
• State-specific logic should be isolated
• You want cleaner and more extensible code

Common Programming Problems Solved by State Pattern

• Workflow engines
• Media player states
• Traffic light systems
• ATM machine operations
• Document approval processes
• Order processing systems
• Character behavior in games
• UI component state handling

Structure of State Pattern in C#

Typical participants:

• Context
• State Interface
• Concrete States
• Client

Basic workflow:

• Context maintains current state
• Client sends request to context
• Context delegates behavior to current state
• State may change context to another state

State Pattern Examples in C#

Example 1: Traffic Light System

A traffic light should behave differently depending on its current color state.

using System;

public interface ITrafficLightState
{
    void Handle(TrafficLight light);
}

public class RedState : ITrafficLightState
{
    public void Handle(TrafficLight light)
    {
        Console.WriteLine("Red Light - Stop");
        light.State = new GreenState();
    }
}

public class GreenState : ITrafficLightState
{
    public void Handle(TrafficLight light)
    {
        Console.WriteLine("Green Light - Go");
        light.State = new YellowState();
    }
}

public class YellowState : ITrafficLightState
{
    public void Handle(TrafficLight light)
    {
        Console.WriteLine("Yellow Light - Wait");
        light.State = new RedState();
    }
}

public class TrafficLight
{
    public ITrafficLightState State { get; set; }

    public TrafficLight()
    {
        State = new RedState();
    }

    public void Change()
    {
        State.Handle(this);
    }
}

public class Program
{
    public static void Main()
    {
        TrafficLight light = new TrafficLight();

        light.Change();
        light.Change();
        light.Change();
    }
}

Example 2: Media Player States

A media player should behave differently when playing, paused, or stopped.

using System;

public interface IPlayerState
{
    void PressButton(MediaPlayer player);
}

public class PlayingState : IPlayerState
{
    public void PressButton(MediaPlayer player)
    {
        Console.WriteLine("Pausing media");
        player.State = new PausedState();
    }
}

public class PausedState : IPlayerState
{
    public void PressButton(MediaPlayer player)
    {
        Console.WriteLine("Resuming media");
        player.State = new PlayingState();
    }
}

public class StoppedState : IPlayerState
{
    public void PressButton(MediaPlayer player)
    {
        Console.WriteLine("Starting media");
        player.State = new PlayingState();
    }
}

public class MediaPlayer
{
    public IPlayerState State { get; set; }

    public MediaPlayer()
    {
        State = new StoppedState();
    }

    public void PressPlayPause()
    {
        State.PressButton(this);
    }
}

public class Program
{
    public static void Main()
    {
        MediaPlayer player = new MediaPlayer();

        player.PressPlayPause();
        player.PressPlayPause();
        player.PressPlayPause();
    }
}

Example 3: Order Processing Workflow

An order should transition through different processing states.

using System;

public interface IOrderState
{
    void Next(Order order);
}

public class NewOrderState : IOrderState
{
    public void Next(Order order)
    {
        Console.WriteLine("Order confirmed");
        order.State = new ShippedState();
    }
}

public class ShippedState : IOrderState
{
    public void Next(Order order)
    {
        Console.WriteLine("Order delivered");
        order.State = new DeliveredState();
    }
}

public class DeliveredState : IOrderState
{
    public void Next(Order order)
    {
        Console.WriteLine("Order already delivered");
    }
}

public class Order
{
    public IOrderState State { get; set; }

    public Order()
    {
        State = new NewOrderState();
    }

    public void Process()
    {
        State.Next(this);
    }
}

public class Program
{
    public static void Main()
    {
        Order order = new Order();

        order.Process();
        order.Process();
        order.Process();
    }
}

Most Known Real-World Use Cases in C#

• Workflow engines
• Game character behavior systems
• Media player controls
• ATM systems
• UI state management
• Document lifecycle systems
• Order processing systems
• Authentication state management
• Network connection state handling

Advantages of State Pattern in C#

• Eliminates complex conditional statements
• Improves code organization
• Encapsulates state-specific behavior
• Simplifies adding new states
• Supports Open/Closed Principle
• Improves readability
• Makes transitions explicit
• Enhances maintainability

Disadvantages (Weak Points) of State Pattern in C#

• Increases number of classes
• Can become complex with many states
• State transitions may be difficult to track
• Adds extra abstraction
• Overkill for simple state logic
• Context-state coupling may grow
• Debugging transitions can become harder

Comparison with Similar Patterns

Pattern Main Purpose Behavior Change State Awareness Typical Usage Main Difference from State
State Change behavior by internal state Dynamic High Workflows, FSMs, UI states Behavior changes automatically based on state
Strategy Choose algorithm dynamically Manual selection Low Sorting, payment processing Strategies are selected externally rather than state-driven
Memento Save and restore object state No Moderate Undo/redo systems Focuses on snapshot restoration instead of behavior changes
Command Encapsulate operations No Low Task queues, undo systems Encapsulates requests instead of state behavior
Template Method Define algorithm skeleton Partial Low Framework base classes Uses inheritance instead of runtime state switching

Simplified UML-Style Structure

Component Responsibility
Context Maintains current state and delegates requests
State Interface Defines state-specific operations
ConcreteState Implements behavior for a specific state
Client Interacts with context object