Real-Time Examples of State Design Pattern in C#

Real-Time Examples of State Design Patterns in C#

In this article, I will discuss Real-Time Examples of State Design Patterns in C#. Please read our previous article discussing the basic concepts of State Design Patterns in C# with Examples. At the end of this article, we will implement the following real-time examples using the State Design Pattern in C#.

  1. Order Processing System
  2. Mobile Phone Ringer
  3. ATM Machine
  4. Traffic Light System
  5. Document Management
  6. Audio Player Context
  7. Product Lifecycle in an E-commerce Platform
Real-Time Example of State Design Pattern in C#: Order Processing System

Let’s consider the classic example of an order processing system where an order can be in various states, such as “New”, “Processed”, “Shipped”, “Delivered”, and “Canceled”. Each state will have different actions that can be performed and will transition to different states based on those actions. Here’s how the State Design Pattern can be applied:

  • State Interface: This defines general actions performed on an order.
  • Concrete State Classes: These classes implement the State interface for each order’s states.
  • Context: This represents the order itself.

Let us see how we can implement the above example using the State Design Pattern using C#:

using System;
namespace StateDesignPattern
{
    // State Interface
    public interface IOrderState
    {
        void Next(Order order);
        void Prev(Order order);
        void PrintStatus();
    }

    // Concrete State Classes
    public class New : IOrderState
    {
        public void Next(Order order)
        {
            order.SetState(new Processed());
        }

        public void Prev(Order order)
        {
            Console.WriteLine("The order is in its new state.");
        }

        public void PrintStatus()
        {
            Console.WriteLine("Order is in NEW state.");
        }
    }

    public class Processed : IOrderState
    {
        public void Next(Order order)
        {
            order.SetState(new Shipped());
        }

        public void Prev(Order order)
        {
            order.SetState(new New());
        }

        public void PrintStatus()
        {
            Console.WriteLine("Order is PROCESSED.");
        }
    }

    public class Shipped : IOrderState
    {
        public void Next(Order order)
        {
            order.SetState(new Delivered());
        }

        public void Prev(Order order)
        {
            order.SetState(new Processed());
        }

        public void PrintStatus()
        {
            Console.WriteLine("Order is SHIPPED.");
        }
    }

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

        public void Prev(Order order)
        {
            order.SetState(new Shipped());
        }

        public void PrintStatus()
        {
            Console.WriteLine("Order is DELIVERED.");
        }
    }

    public class Canceled : IOrderState
    {
        public void Next(Order order)
        {
            Console.WriteLine("Order is canceled and cannot proceed.");
        }

        public void Prev(Order order)
        {
            Console.WriteLine("Order is canceled and cannot go back.");
        }

        public void PrintStatus()
        {
            Console.WriteLine("Order is CANCELED.");
        }
    }

    // Context
    public class Order
    {
        private IOrderState _currentState;

        public Order()
        {
            _currentState = new New();
        }

        public void SetState(IOrderState state)
        {
            _currentState = state;
        }

        public void NextState()
        {
            _currentState.Next(this);
        }

        public void PrevState()
        {
            _currentState.Prev(this);
        }

        public void PrintStatus()
        {
            _currentState.PrintStatus();
        }
    }

    // Test the State Pattern
    public class Program
    {
        public static void Main(string[] args)
        {
            Order order = new Order();

            order.PrintStatus();  // Output: Order is in NEW state.

            order.NextState();
            order.PrintStatus();  // Output: Order is PROCESSED.

            order.NextState();
            order.PrintStatus();  // Output: Order is SHIPPED.

            order.PrevState();
            order.PrintStatus();  // Output: Order is PROCESSED.

            order.SetState(new Canceled());
            order.PrintStatus();  // Output: Order is CANCELED.

            Console.ReadKey();
        }
    }
}

In this example, we have modeled an order processing system where an order can transition through different states. Using the State Design Pattern, the behavior of the order changes based on its current state. When you run the above code, you will get the following output.

Real-Time Example of State Design Pattern in C#: Order Processing System

Real-Time Examples of State Design Pattern in C#: Mobile Phone Ringer

Let’s dive into a real-time example of the State Design Pattern by considering a mobile phone ringer. Mobile phones often have different ringer modes like “Silent”, “Vibration”, and “Ringing”. Depending on the mode, the behavior of an incoming call will differ. Using the State Design Pattern, we can easily model this behavior:

  • State Interface: This defines the behavior when there’s an incoming call.
  • Concrete State Classes: These implement the State interface for “Silent”, “Vibration”, and “Ringing” modes.
  • Context: This represents the mobile phone itself.

Let us see how we can implement the above example using the State Design Pattern using C#:

using System;
namespace StateDesignPattern
{
    // State Interface
    public interface IRingerState
    {
        void HandleIncomingCall();
    }

    // Concrete State Classes
    public class Silent : IRingerState
    {
        public void HandleIncomingCall()
        {
            Console.WriteLine("No Sound. Flash notification light.");
        }
    }

    public class Vibration : IRingerState
    {
        public void HandleIncomingCall()
        {
            Console.WriteLine("Vibrate The Phone.");
        }
    }

    public class Ringing : IRingerState
    {
        public void HandleIncomingCall()
        {
            Console.WriteLine("Play The Ringtone.");
        }
    }

    // Context
    public class MobilePhone
    {
        private IRingerState _currentState;

        public MobilePhone()
        {
            // Default state
            _currentState = new Ringing();
        }

        public void SetState(IRingerState state)
        {
            _currentState = state;
        }

        public void IncomingCall()
        {
            _currentState.HandleIncomingCall();
        }
    }

    // Test the State Pattern
    public class Program
    {
        public static void Main(string[] args)
        {
            MobilePhone phone = new MobilePhone();

            phone.IncomingCall(); // Output: Play The Ringtone.

            phone.SetState(new Silent());
            phone.IncomingCall(); // Output: No Sound. Flash notification light.

            phone.SetState(new Vibration());
            phone.IncomingCall(); // Output: Vibrate The Phone.

            Console.ReadKey();
        }
    }
}

In this example, the behavior of the mobile phone during an incoming call is determined by its ringer state. Using the State Design Pattern, the code remains flexible and easy to understand. If, in the future, a new ringer mode needs to be introduced (e.g., “Do Not Disturb”), it’s straightforward to implement without changing the existing states or the MobilePhone context. When you run the above code, you will get the following output.

Real-Time Examples of State Design Pattern in C#: Mobile Phone Ringer

Real-Time Example of State Design Pattern in C#: ATM Machine

An ATM can be in various states: “NoCard”, “CardInserted”, “PinVerified”, and “TransactionCompleted”. Here’s how we can model this behavior using the State Design Pattern:

  • State Interface: This defines general ATM actions.
  • Concrete State Classes: Implementing the State interface for each of the states.
  • Context: This represents the ATM machine itself.

Let us see how we can implement the above example using the State Design Pattern using C#:

using System;
namespace StateDesignPattern
{
    // State Interface
    public interface IATMState
    {
        void InsertCard();
        void EjectCard();
        void EnterPin();
        void WithdrawMoney();
    }

    // Concrete State Classes
    public class NoCard : IATMState
    {
        public void InsertCard()
        {
            Console.WriteLine("Card Inserted. Please Enter the PIN.");
        }

        public void EjectCard()
        {
            Console.WriteLine("No Card to Eject.");
        }

        public void EnterPin()
        {
            Console.WriteLine("Please Insert Card First.");
        }

        public void WithdrawMoney()
        {
            Console.WriteLine("Insert and Verify Card to Withdraw Money.");
        }
    }

    public class CardInserted : IATMState
    {
        public void InsertCard()
        {
            Console.WriteLine("Card is Already Inserted.");
        }

        public void EjectCard()
        {
            Console.WriteLine("Card Ejected.");
        }

        public void EnterPin()
        {
            Console.WriteLine("PIN Accepted. You can now Withdraw Money.");
        }

        public void WithdrawMoney()
        {
            Console.WriteLine("Please Enter the PIN First.");
        }
    }

    public class PinVerified : IATMState
    {
        public void InsertCard()
        {
            Console.WriteLine("Card is Already Inserted.");
        }

        public void EjectCard()
        {
            Console.WriteLine("Card Ejected.");
        }

        public void EnterPin()
        {
            Console.WriteLine("PIN Already Verified.");
        }

        public void WithdrawMoney()
        {
            Console.WriteLine("Money Withdrawn. Card will be Ejected.");
        }
    }

    // Context
    public class ATM
    {
        private IATMState _currentState;

        public ATM()
        {
            // Default state
            _currentState = new NoCard();
        }

        public void SetState(IATMState state)
        {
            _currentState = state;
        }

        public void InsertCard()
        {
            _currentState.InsertCard();
        }

        public void EjectCard()
        {
            _currentState.EjectCard();
        }

        public void EnterPin()
        {
            _currentState.EnterPin();
        }

        public void WithdrawMoney()
        {
            _currentState.WithdrawMoney();
        }
    }

    // Test the State Pattern
    public class Program
    {
        public static void Main(string[] args)
        {
            ATM atm = new ATM();

            atm.InsertCard();  // Output: Card Inserted. Please Enter the PIN.

            atm.SetState(new CardInserted());
            atm.EnterPin();    // Output: PIN accepted. You can now Withdraw Money.

            atm.SetState(new PinVerified());
            atm.WithdrawMoney();  // Output: Money Withdrawn. Card will be Ejected.

            atm.EjectCard();   // Output: Card Ejected.
            Console.ReadKey();
        }
    }
}

This example shows an ATM machine’s typical actions, where the actions’ results change based on the machine’s current state. The State Design Pattern helps cleanly implement the changing behavior with the ATM’s state, making the code flexible and maintainable. When you run the above code, you will get the following output.

Real-Time Example of State Design Pattern in C#: Traffic Light System

The traffic light typically transitions between three states: “Red”, “Yellow”, and “Green”. Each state has a specific behavior, and the transition follows a pattern. Here’s how the State Design Pattern can be used:

  • State Interface: Defines a method for transitioning to the next state.
  • Concrete State Classes: Implement the State interface for each traffic light state.
  • Context: Represents the traffic light system that will change its behavior based on its current state.

Let us see how we can implement the above example using the State Design Pattern using C#:

using System;
namespace StateDesignPattern
{
    // State Interface
    public interface ITrafficLightState
    {
        void TransitionToNextState(TrafficLight trafficLight);
        void DisplayState();
    }

    // Concrete State Classes
    public class Red : ITrafficLightState
    {
        public void TransitionToNextState(TrafficLight trafficLight)
        {
            trafficLight.SetState(new Green());
        }

        public void DisplayState()
        {
            Console.WriteLine("Traffic Light is RED. Cars should STOP.");
        }
    }

    public class Green : ITrafficLightState
    {
        public void TransitionToNextState(TrafficLight trafficLight)
        {
            trafficLight.SetState(new Yellow());
        }

        public void DisplayState()
        {
            Console.WriteLine("Traffic Light is GREEN. Cars can GO.");
        }
    }

    public class Yellow : ITrafficLightState
    {
        public void TransitionToNextState(TrafficLight trafficLight)
        {
            trafficLight.SetState(new Red());
        }

        public void DisplayState()
        {
            Console.WriteLine("Traffic Light is YELLOW. Cars should get ready to STOP.");
        }
    }

    // Context
    public class TrafficLight
    {
        private ITrafficLightState _currentState;

        public TrafficLight()
        {
            // Initial state
            _currentState = new Red();
        }

        public void SetState(ITrafficLightState state)
        {
            _currentState = state;
        }

        public void ChangeState()
        {
            _currentState.TransitionToNextState(this);
        }

        public void DisplayCurrentState()
        {
            _currentState.DisplayState();
        }
    }

    // Test the State Pattern
    public class Program
    {
        public static void Main(string[] args)
        {
            TrafficLight trafficLight = new TrafficLight();

            trafficLight.DisplayCurrentState(); // Output: Traffic Light is RED. Cars should STOP.

            trafficLight.ChangeState();
            trafficLight.DisplayCurrentState(); // Output: Traffic Light is GREEN. Cars can GO.

            trafficLight.ChangeState();
            trafficLight.DisplayCurrentState(); // Output: Traffic Light is YELLOW. Cars should get ready to STOP.

            trafficLight.ChangeState();
            trafficLight.DisplayCurrentState(); // Output: Traffic Light is RED. Cars should STOP.

            Console.ReadKey();
        }
    }
}

In this example, the traffic light system is modeled, and its behavior changes based on its current state. Using the State Design Pattern, the system can easily transition between states and is clear and maintainable. When you run the above code, you will get the following output.

Real-Time Example of State Design Pattern in C#: Traffic Light System

Real-Time Example of State Design Pattern in C#: Document Management

Let’s take a look at another real-world example, document management. Let’s say we have a document that can be in one of several states, such as “Draft”, “Review”, “Approved”, or “Rejected”. Here’s how we can use the State Design Pattern to model this behavior:

  • State Interface: This defines operations like “Publish”, “Modify”, and “Archive”.
  • Concrete State Classes: These implement the State interface for each document state.
  • Context: Represents the document.

Let us see how we can implement the above example using the State Design Pattern using C#:

using System;
namespace StateDesignPattern
{
    // State Interface
    public interface IDocumentState
    {
        void Publish();
        void Modify(string content);
        void Archive();
    }

    // Concrete State Classes
    public class Draft : IDocumentState
    {
        public void Publish()
        {
            Console.WriteLine("Document is now in review.");
        }

        public void Modify(string content)
        {
            Console.WriteLine($"Document modified with content: {content}");
        }

        public void Archive()
        {
            Console.WriteLine("Draft cannot be archived.");
        }
    }

    public class Review : IDocumentState
    {
        public void Publish()
        {
            Console.WriteLine("Document is approved and published.");
        }

        public void Modify(string content)
        {
            Console.WriteLine("Document under review cannot be modified.");
        }

        public void Archive()
        {
            Console.WriteLine("Document under review is archived.");
        }
    }

    public class Approved : IDocumentState
    {
        public void Publish()
        {
            Console.WriteLine("Document is already published.");
        }

        public void Modify(string content)
        {
            Console.WriteLine("Published document modified with content: " + content);
        }

        public void Archive()
        {
            Console.WriteLine("Published document is archived.");
        }
    }

    public class Rejected : IDocumentState
    {
        public void Publish()
        {
            Console.WriteLine("Rejected document cannot be published.");
        }

        public void Modify(string content)
        {
            Console.WriteLine($"Rejected document modified with content: {content}");
        }

        public void Archive()
        {
            Console.WriteLine("Rejected document is archived.");
        }
    }

    // Context
    public class Document
    {
        private IDocumentState _currentState;

        public Document()
        {
            // Initial state
            _currentState = new Draft();
        }

        public void SetState(IDocumentState state)
        {
            _currentState = state;
        }

        public void Publish()
        {
            _currentState.Publish();
        }

        public void Modify(string content)
        {
            _currentState.Modify(content);
        }

        public void Archive()
        {
            _currentState.Archive();
        }
    }

    // Testing the State Pattern
    public class Program
    {
        public static void Main(string[] args)
        {
            Document doc = new Document();

            doc.Publish();  // Output: Document is now in review.
            doc.Archive();  // Output: Document under review is archived.

            doc.SetState(new Approved());
            doc.Publish();  // Output: Document is already published.
            doc.Modify("New updates");  // Output: Published document modified with content: New updates

            doc.SetState(new Rejected());
            doc.Publish();  // Output: Rejected document cannot be published.

            Console.ReadKey();
        }
    }
}

This example models the typical lifecycle of a document in a document management system. The State Design Pattern provides a clean way to define different behaviors based on the document’s state. When you run the above code, you will get the following output.

Real-Time Example of State Design Pattern in C#: Document Management

Real-Time Examples of State Design Pattern in C#: Audio Player Context

Let us see a real-world scenario where the State Design Pattern can be applied, i.e., Audio Player Context. Suppose you’re designing an audio player. It can have multiple states like “Playing”, “Paused”, “Stopped”, and “Locked”.

  • State Interface: Defines operations like “Play”, “Stop”, “Lock”, and “Next”.
  • Concrete State Classes: Implement the State interface for each audio player state.
  • Context: Represents the audio player.

Let us see how we can implement the above example using the State Design Pattern using C#:

using System;
namespace StateDesignPattern
{
    // State Interface
    public interface IPlayerState
    {
        void Play();
        void Stop();
        void Lock();
        void Next();
    }

    // Concrete State Classes
    public class Playing : IPlayerState
    {
        public void Play() => Console.WriteLine("Already playing!");
        public void Stop() => Console.WriteLine("Stopped the player.");
        public void Lock() => Console.WriteLine("Player locked while playing.");
        public void Next() => Console.WriteLine("Switched to the next track.");
    }

    public class Paused : IPlayerState
    {
        public void Play() => Console.WriteLine("Resumed playing.");
        public void Stop() => Console.WriteLine("Stopped the player.");
        public void Lock() => Console.WriteLine("Player locked while paused.");
        public void Next() => Console.WriteLine("Switched to the next track.");
    }

    public class Stopped : IPlayerState
    {
        public void Play() => Console.WriteLine("Started playing from the beginning.");
        public void Stop() => Console.WriteLine("Already stopped!");
        public void Lock() => Console.WriteLine("Player is locked and stopped.");
        public void Next() => Console.WriteLine("Can't switch, the player is stopped.");
    }

    public class Locked : IPlayerState
    {
        public void Play() => Console.WriteLine("Unlock the player first.");
        public void Stop() => Console.WriteLine("Unlock the player first.");
        public void Lock() => Console.WriteLine("Already locked!");
        public void Next() => Console.WriteLine("Unlock the player first.");
    }

    // Context
    public class AudioPlayer
    {
        private IPlayerState _currentState = new Stopped();

        public void SetState(IPlayerState state) => _currentState = state;

        public void Play() => _currentState.Play();
        public void Stop() => _currentState.Stop();
        public void Lock() => _currentState.Lock();
        public void Next() => _currentState.Next();
    }

    // Testing the State Pattern
    public class Program
    {
        public static void Main(string[] args)
        {
            AudioPlayer audioPlayer = new AudioPlayer();

            audioPlayer.Play();
            audioPlayer.Stop();
            
            audioPlayer.SetState(new Paused());
            audioPlayer.Play();  
            audioPlayer.Next(); 
            audioPlayer.Lock();
            
            Console.ReadKey();
        }
    }
}
Output:

Real-Time Examples of State Design Pattern in C#: Audio Player Context

Real-Time Examples of State Design Pattern in C#: Product Lifecycle in an E-commerce Platform

Think of a product on an online marketplace. It can have states like “Draft”, “Live”, “Out of Stock”, and “Archived”.

  • State Interface: Describes actions such as “Publish”, “Restock”, “SellOut”, and “Archive”.
  • Concrete State Classes: Implement the State interface for each product state.
  • Context: Represents the product.

Let us see how we can implement the above example using the State Design Pattern using C#:

using System;
namespace StateDesignPattern
{
    // State Interface
    public interface IProductState
    {
        void Publish();
        void Restock();
        void SellOut();
        void Archive();
    }

    // Concrete State Classes
    public class Draft : IProductState
    {
        public void Publish() => Console.WriteLine("Product is now live.");
        public void Restock() => Console.WriteLine("Draft products can't be restocked.");
        public void SellOut() => Console.WriteLine("Draft products can't be sold out.");
        public void Archive() => Console.WriteLine("Draft product archived.");
    }

    public class Live : IProductState
    {
        public void Publish() => Console.WriteLine("Product is already live.");
        public void Restock() => Console.WriteLine("Product restocked.");
        public void SellOut() => Console.WriteLine("Product is now out of stock.");
        public void Archive() => Console.WriteLine("Live product archived.");
    }

    public class OutOfStock : IProductState
    {
        public void Publish() => Console.WriteLine("Out of stock product can't be published.");
        public void Restock() => Console.WriteLine("Product is back in stock and live.");
        public void SellOut() => Console.WriteLine("Product is already out of stock.");
        public void Archive() => Console.WriteLine("Out of stock product archived.");
    }

    public class Archived : IProductState
    {
        public void Publish() => Console.WriteLine("Archived product can't be published.");
        public void Restock() => Console.WriteLine("Archived products can't be restocked.");
        public void SellOut() => Console.WriteLine("Archived products can't be sold out.");
        public void Archive() => Console.WriteLine("Product is already archived.");
    }

    // Context
    public class Product
    {
        private IProductState _currentState = new Draft();

        public void SetState(IProductState state) => _currentState = state;

        public void Publish() => _currentState.Publish();
        public void Restock() => _currentState.Restock();
        public void SellOut() => _currentState.SellOut();
        public void Archive() => _currentState.Archive();
    }
    
    // Testing the State Pattern
    public class Program
    {
        public static void Main(string[] args)
        {
            Product product = new Product();

            product.Publish();
            product.SellOut();

            product.SetState(new OutOfStock());
            product.Restock();
            product.SellOut();
            product.Archive(); 
            
            Console.ReadKey();
        }
    }
}
Output:

Real-Time Examples of State Design Pattern in C#: Product Lifecycle in an E-commerce Platform

The Task for You:

This real-time example is a task for you guys. I will explain the concept with the diagram, and I expect you guys to do the program implementation and provide your code in the comment section.

TV Remote control is one of the best examples of the State Design Pattern. Using the TV Remote Control, we can switch on and off the TV. That means the Remote control internally maintains two states (i.e., On and Off). For example, when the internal state is On, it will be on the TV, as shown below.

The Task for You

Similarly, when the state is Off, it will turn off the TV, as shown below.

The Task for You

When to use State Design Patterns in Real-Time Applications?

The State Design Pattern is highly beneficial when an object needs to alter its behavior based on its internal state. By isolating state-specific behaviors into separate objects, the pattern promotes cleaner code and makes it easier to extend and maintain. Here are situations in real-time applications when the State Design Pattern can be useful:

  • Finite State Machines: Any system described as a finite state machine (FSM) can benefit from the State Pattern. Examples include vending machines, traffic lights, and game logic.
  • UI Components: Graphical user interfaces often have components that exhibit different behaviors based on their state. For instance, a button might have states like “normal”, “hovered”, “pressed”, or “disabled”, each of which might trigger different visuals or actions.
  • Modes in Applications: If an application can operate in different modes and its behavior differs in each mode, the State Pattern can be handy. For instance, a graphics editor might have modes like “select”, “draw”, “erase”, and so forth.
  • TCP Connection States: A TCP connection goes through various states like “LISTEN”, “SYN-SENT”, “ESTABLISHED”, and “CLOSE-WAIT”. Using the State Pattern, the behavior of the connection can be cleanly handled for each state.
  • Workflow Processes: Systems that handle workflows, such as document approval processes or order processing systems, can often be modeled with states, where each state represents a stage in the workflow.
  • Media Players: Consider a media player who can have states like “play”, “pause”, “stop”, “rewind”, etc. The actions or events like “next” or “prev” can behave differently depending on the current state.
  • Authentication Systems: Systems where user access levels change, such as logging in, logging out, or when privileges are elevated.
  • Game Development: Games often have objects with state-dependent behaviors, such as characters that can be in states like “idle”, “running”, “jumping”, “attacking”, etc.

Using the State Pattern in these contexts has several advantages:

  • Encapsulation of State-Specific Behavior: This ensures that state-related code is not spread throughout the main class, reducing the risk of errors.
  • Ease of Extension: Introducing new states without altering existing state classes or the context class is simpler.
  • Separation of Concerns: Each state class focuses solely on its own behavior.
  • Increased Maintainability: As behaviors are isolated in state classes, making changes or troubleshooting state-related bugs becomes simpler.

However, remember not to overuse this pattern. If your object doesn’t switch between states frequently, or if there are only a few simple conditions to check, the overhead of setting up the State Pattern might outweigh its benefits. So, we need to use the State Design Pattern in Real-Time Applications when

  1. We need to change the behavior of an object based on its internal state.
  2. We need to provide flexibility in assigning requests to handlers.
  3. An object is becoming more complex with many conditional statements.

In the next article, I will discuss the Template Design Pattern in C# with Examples. Here, in this article, I try to explain the Real-Time Examples of State Design Patterns in C#. I hope you enjoy this State Design Pattern in Real-time Examples using the C# article.

7 thoughts on “Real-Time Examples of State Design Pattern in C#”

  1. Hi, thank you for your tutorial, and these are always helpful for me. Here is my work, please look at this.

    using System;

    namespace StateDemo
    {
    public interface IRemoteControll
    {
    void TurnOn();
    void TurnOff();
    }

    public class StateTurnOn : IRemoteControll
    {
    public void TurnOn()
    {
    Console.WriteLine(“TV is already turned on. Nothing to do.”);
    }

    public void TurnOff()
    {
    Console.WriteLine(“TV is successfully turned off.”);
    }
    }

    public class StateTurnOff : IRemoteControll
    {
    public void TurnOn()
    {
    Console.WriteLine(“TV is successfully turned on.”);

    }

    public void TurnOff()
    {
    Console.WriteLine(“TV is already turned off. Nothing to do.”);
    }
    }

    public class RemoteController:IRemoteControll
    {
    private IRemoteControll rState;
    private IRemoteControll stateTurnOn = new StateTurnOn();
    private IRemoteControll stateTurnOff = new StateTurnOff();

    public RemoteController()
    {
    rState = new StateTurnOff();
    }

    public void TurnOn()
    {
    rState.TurnOn();
    if (rState is StateTurnOff)
    {
    rState = stateTurnOn;
    }

    }

    public void TurnOff()
    {
    rState.TurnOff();
    if (rState is StateTurnOn)
    {
    rState = stateTurnOff;
    }
    }
    }
    }

    using System;

    namespace StateDemo
    {
    class Program
    {
    static void Main(string[] args)
    {
    IRemoteControll remoteControll = new RemoteController();

    remoteControll.TurnOff();

    remoteControll.TurnOn();

    remoteControll.TurnOff();

    remoteControll.TurnOff();

    remoteControll.TurnOn();
    }
    }
    }

  2. The example of this article accumulates the state objects in the memory. Your example solved the problem. Another example also creates a new instance whenever it changes the state.

  3. Thank you very much for explaining everything so well. My code:
    public interface IButtonPowerTV
    {
    public void clickButtonPower();
    }
    public class SwitchedOnTV: IButtonPowerTV
    {
    public void clickButtonPower()
    {
    Console.Writeln(“TV has been switched OFF”);
    }
    }
    public class SwitchedOffTV: IButtonPowerTV
    {
    public void clickButtonPower()
    {
    Console.Writeln(“TV has been switched ON”);
    }
    }
    public class ContextButtonPowerTV: IButtonPowerTV
    {
    private IButtonPowerTV StateTV;
    public ContextButtonPowerTV()
    {
    StateTV = new SwitchedOffTV();
    }
    public void clickButtonPower()
    {
    StateTV.clickButtonPower();
    if(StateTV is SwitchedOffTV)´
    {
    StateTV = new SwitchedOnTV();
    Console.Writeln($”State has changed to {SwitchedOnTV.GetType().Name}”);
    }
    else
    {
    StateTV = new SwitchedOffTV();
    Console.Writeln($”State has changed to {SwitchedOffTV.GetType().Name}”);
    }

    }
    }

  4. State Interface (ITVRemote.cs) :
    namespace RemoteTV
    {
    public interface ITVRemote
    {
    void OpenStatus();
    }
    }
    Concrete State 1 (CloseState.cs) :
    namespace RemoteTV
    {
    public class CloseState : ITVRemote
    {
    public void OpenStatus()
    {
    Console.WriteLine(“TV is close.”);
    }
    }
    }
    Concrete State 2 (OpenState.cs) :
    namespace RemoteTV
    {
    public class OpenState : ITVRemote
    {
    public void OpenStatus()
    {
    Console.WriteLine(“TV is open.”);
    }
    }
    }
    Context (TV.cs) :
    namespace RemoteTV
    {
    public class TV : ITVRemote
    {
    public ITVRemote TVState { get; set; }
    public TV()
    {
    TVState = new CloseState();
    }
    public void OpenStatus()
    {
    TVState.OpenStatus();

    if (TVState is CloseState)
    {
    TVState = new OpenState();
    Console.WriteLine($”TV has opened. Current status is {TVState.GetType().Name}”);
    }
    }
    public void CloseStatus()
    {
    TVState.OpenStatus();

    if (TVState is OpenState)
    {
    TVState = new CloseState();
    Console.WriteLine($”TV has closed. Current status is {TVState.GetType().Name}”);
    }
    }
    }
    }
    Client (Program.cs) :
    namespace RemoteTV
    {
    class Program
    {
    static void Main(string[] args)
    {
    TV television = new TV();
    Console.WriteLine($”Current TV State : {television.TVState.GetType().Name}\n”);
    television.CloseStatus();
    Console.WriteLine(“—————————————“);

    television.OpenStatus();
    Console.WriteLine($”Current TV State : {television.TVState.GetType().Name}\n”);
    Console.WriteLine(“—————————————“);

    television.OpenStatus();
    Console.WriteLine(“—————————————“);
    television.CloseStatus();
    Console.WriteLine($”Current TV State : {television.TVState.GetType().Name}\n”);

    Console.ReadKey();

    }
    }
    }

  5. Thank you for your wonderful articles and pattern descriptions !
    I have a question, in the first description of the State pattern, when implementing the pattern for a context object you inherited the State Interface, in these examples there is no such thing, hint what is correct ?
    Or are all these variants correct ? Since the description of the pattern from the gang of four does not say anything about strict inheritance and in the first example we could also not perform any inheritance ? And the essence of the pattern is that there is a context object with state options, and the context object performs processing or actions on the data depending on the state ?

  6. void Main()
    {
    RemoteControl panasonicRemoteControl = new RemoteControl();
    panasonicRemoteControl.DisplayStatus();
    panasonicRemoteControl.PressPowerButton();
    panasonicRemoteControl.DisplayStatus();
    panasonicRemoteControl.PressPowerButton();
    panasonicRemoteControl.DisplayStatus();
    }

    public interface ITVPowerStatus
    {
    public void PowerButton();
    public void DisplayStatus();
    }

    public class TurnOnTV : ITVPowerStatus
    {
    public void DisplayStatus()
    {
    Console.WriteLine(“Power status ON”);
    }

    public void PowerButton()
    {
    Console.WriteLine(“You turn ON TV !”);
    }
    }

    public class TurnOffTV : ITVPowerStatus
    {
    public void DisplayStatus()
    {
    Console.WriteLine(“Power status OFF”);
    }
    public void PowerButton()
    {
    Console.WriteLine(“You Turn OFF TV !”);
    }
    }

    public class RemoteControl
    {
    private ITVPowerStatus _tvStatus;

    public RemoteControl() => _tvStatus = new TurnOffTV();

    public void PressPowerButton()
    {
    _tvStatus = _tvStatus switch
    {
    TurnOffTV turnOff => new TurnOnTV(),
    TurnOnTV turnOn => new TurnOffTV(),
    _ => null
    };
    _tvStatus.PowerButton();
    }
    public void DisplayStatus()
    {
    _tvStatus.DisplayStatus();
    }
    }

  7. Having studied the pattern documentation again, the question appeared, how much is it correct to change the internal state of the context object, sealing the usage by switching states inside the context object ?
    Maybe it is more correct to manage state switching through an open method with the context object argument ?

Leave a Reply

Your email address will not be published. Required fields are marked *