Blog / Design Patterns
The State Design Pattern in C# and .Net
  • Jan 04, 2021
  • 54
  • 81

The next design pattern in the Behavioral Category is the State Design Pattern. Let's take a look at the definition of this design pattern and how to implement it in C# and .Net.

Note: Code can be downloaded at my Github.


Advertisement
 


1. What is the State Design Pattern?

State is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.

The state pattern is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. This pattern is close to the concept of finite-state machines.


2. When to implement the State Design Pattern?

The State Design Pattern should be implemented when:

  • you have an object that behaves differently depending on its current state, the number of states is enormous, and the state-specific code changes frequently.
  • you have a class polluted with massive conditionals that alter how the class behaves according to the current values of the class’s fields.
  • you have a lot of duplicate code across similar states and transitions of a condition-based state machine.


3. How to implement the State Design Pattern?

Below is how to implement the State Design Pattern in C# and .Net:

Step 1: Create a Context class

The Context defines the interface of interest to clients. It also maintains a reference to an instance of a State subclass, which represents the current state of the Context.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Context
{
    // A reference to the current state of the Context.
    private State _state = null;
 
    public Context(State state)
    {
        this.TransitionTo(state);
    }
 
    // The Context allows changing the State object at runtime.
    public void TransitionTo(State state)
    {
        Console.WriteLine($"Context: Transition to {state.GetType().Name}.");
        this._state = state;
        this._state.SetContext(this);
    }
 
    // The Context delegates part of its behavior to the current State
    // object.
    public void Request1()
    {
        this._state.Handle1();
    }
 
    public void Request2()
    {
        this._state.Handle2();
    }
}


Step 2: Create State classes

The base State class declares methods that all Concrete State should implement and also provides a backreference to the Context object, associated with the State. This backreference can be used by States to transition the Context to another State.

1
2
3
4
5
6
7
8
9
10
11
12
13
abstract class State
{
    protected Context _context;
 
    public void SetContext(Context context)
    {
        this._context = context;
    }
 
    public abstract void Handle1();
 
    public abstract void Handle2();
}

Concrete States implement various behaviors, associated with a state of the Context.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class ConcreteStateA : State
{
    public override void Handle1()
    {
        Console.WriteLine("ConcreteStateA handles request1.");
        Console.WriteLine("ConcreteStateA wants to change the state of the context.");
        this._context.TransitionTo(new ConcreteStateB());
    }
 
    public override void Handle2()
    {
        Console.WriteLine("ConcreteStateA handles request2.");
    }
}
 
class ConcreteStateB : State
{
    public override void Handle1()
    {
        Console.Write("ConcreteStateB handles request1.");
    }
 
    public override void Handle2()
    {
        Console.WriteLine("ConcreteStateB handles request2.");
        Console.WriteLine("ConcreteStateB wants to change the state of the context.");
        this._context.TransitionTo(new ConcreteStateA());
    }
}

Done, you can now implement this in client:

1
2
3
4
5
6
7
8
9
10
class Program
{
    static void Main(string[] args)
    {
        // The client code.
        var context = new Context(new ConcreteStateA());
        context.Request1();
        context.Request2();
    }
}

Output:



4. Conclusion

I hope this article is helpful for your projects. Please let me know your thoughts by commenting in the section below.


Search text in Stored Procedure in SQL SELECT DISTINCT o.name AS Object_Name, o.type_desc FROM sys.sql_modules m INNER JOIN sys.objects o ON m.object_id = o ...

Using cherry-pick to select specific commits for your Pull Request.1. Create a new branch based on the target of the Pull Requestgit branch cherry-branch origin/master2. Switch to a new branchgit chec ...

After deployment Angular and API on IIS, it's working fine unless I refresh the page. Once refreshed, the web encountered 404 error. In this article, I will explain how to resolve this.Since Angular i ...

There are some benefits of keeping both UI and API parts in the same place for small projects. In this article, I will explain how I did to deploy Angular Web and ASP .Net Core API in the same folder ...

I got CORS error after publishing my API and Angular app to IIS even though CORS is enabled and the origins of the Angular app is added. Below is how I resolved this issue.Just simple, make sure you s ...

1. The Situation:Error Message: Pulse Secure Application failed to load Java. Please install correct JRE version.Description: This issue happens when I'm using a M1 Mac with a correct version of ...

Accelerated Mobile Pages (AMP) focuses on delivering static content from publishers as quickly as possible and possibly rewards early adopters with a boost in rank. Let's see how to implement it ...

Below is how to decrypt/convert a Hex string value into text using VB.Net:Decrypting Hex string value to string in VB.Net Function HexToString(ByVal hex As String) As String Dim text As New Sy ...

After a month of publishing on Google Play, Jungle Words has made it to the Top Android Games To Try Out In April 2021. Please check it out! GameKeys.netGameKeys is a website which introduces gam ...