Tuesday, July 9, 2024

State Design Pattern in C#

The State Design Pattern is a behavioral design pattern that allows an object to alter its behavior when its internal state changes. This pattern is particularly useful for implementing state machines and ensuring that the object’s behavior remains manageable and modular.

This pattern is useful when an object needs to go through several states, and its behavior differs for each state. Instead of having conditional statements throughout a class to handle state-specific behaviors, the State Design Pattern delegates this responsibility to individual state classes.

Components of State Desgin Pattern

  1. Context: This is the class that contains an instance of a state and delegates state-specific behavior to the current state object.
  2. State: An interface that encapsulates the behavior associated with a particular state of the Context.
  3. Concrete States: Classes that implement the State interface, each representing a specific state and defining its behavior.

Example in C#

Let's consider a scenario of a Document that can be in different states: Draft, Moderation, and Published. Depending on the state, the behavior of the Document changes, especially its ability to be published or edited.

Create State Interface (IDocumentState.cs)

First, create an interface that defines the state-specific methods:

using StateDesignPattern.Context;

namespace StateDesignPattern.State
{
    /// <summary>
    /// State Interface
    /// </summary>
    public interface IDocumentState
    {
        void Publish(Document document);
        void Edit(Document document);
    }
}
Implement Concrete States(DraftState.cs, ModerationState.cs, PublishedState.cs)

Next, implement the concrete states. Each state will have its own behavior for the methods defined in the IDocumentState interface:

// DraftState.cs
using StateDesignPattern.Context;

namespace StateDesignPattern.State
{
    //// <summary>
    /// Concrete State1
   /// </summary>
    public class DraftState : IDocumentState
    {
        public void Publish(Document document)
        {
            document.State = new ModerationState();
            Console.WriteLine("Document moved to Moderation state.");
        }

        public void Edit(Document document)
        {
            Console.WriteLine("Document is in Draft state. You can edit the document.");
        }
    }
}

//ModerationState.cs
using StateDesignPattern.Context;

namespace StateDesignPattern.State
{
    //// <summary>
    /// Concrete State2
   /// </summary>
    public class ModerationState : IDocumentState
    {
        public void Publish(Document document)
        {
            document.State = new PublishedState();
            Console.WriteLine("Document moved to Published state.");
        }

        public void Edit(Document document)
        {
            Console.WriteLine("Document is in Moderation state. You cannot edit the document.");
        }
    }
}
// PublishedState.cs
using StateDesignPattern.Context;

namespace StateDesignPattern.State
{
    //// <summary>
    /// Concrete State3
   /// </summary>
    public class PublishedState : IDocumentState
    {
        public void Publish(Document document)
        {
            Console.WriteLine("Document is already published.");
        }

        public void Edit(Document document)
        {
            Console.WriteLine("Document is Published. You cannot edit the document.");
        }
    }
}
Implement the Context (Document.cs)

The Document class will act as the context, holding a reference to the current state:

using StateDesignPattern.State;

namespace StateDesignPattern.Context
{
    public class Document
    {
        public IDocumentState State { get; set; }

        public Document()
        {
            State = new DraftState();
        }

        public void Publish()
        {
            State.Publish(this);
        }

        public void Edit()
        {
            State.Edit(this);
        }
    }
}
Client (Program.cs)

Now, you can create a Document object and see how its behavior changes as its state changes:

using StateDesignPattern.Context;

Document document = new Document();

document.Edit(); // Output: Document is in Draft state. You can edit the document.
document.Publish(); // Output: Document moved to Moderation state.

document.Edit(); // Output: Document is in Moderation state. You cannot edit the document.
document.Publish(); // Output: Document moved to Published state.

document.Edit(); // Output: Document is Published. You cannot edit the document.
document.Publish();
Console.ReadLine();

Output

state design pattern in C# with example

Conclusion

The State Design Pattern is a powerful way to manage state-dependent behavior in an object-oriented design. By encapsulating state-specific behavior into separate classes, you can easily add or modify states without changing the context class or the state interface. This promotes cleaner, more maintainable, and scalable code.

The full source code is available here:

Happy coding!! 😊

No comments:

Post a Comment

^ Scroll to Top