Click here to Skip to main content
12,291,055 members (45,555 online)
Click here to Skip to main content
Add your own
alternative version

Stats

108.2K views
736 downloads
52 bookmarked
Posted

C# - State Pattern Example

, 23 Jun 2005
Rate this:
Please Sign up or sign in to vote.
The State Pattern is a common Object Oriented Design Pattern that allows an object to alter its behavior dynamically by changing its internal state.

Introduction

The State Pattern is a common Object Oriented Design Pattern that allows an object to alter its behavior dynamically by changing its internal state. So the State Pattern is a design pattern; what is a design pattern? A design pattern is an example "blueprint" of a solution to solve a common problem. Why use a design pattern? Design patterns are proven and take design constraints and other factors into account.

The State Pattern can be used in many different circumstances. For instance, a car's automatic transmission must behave differently depending on its speed "state". The difference in behavior is represented by the gears or states. In my example, I use a common machine that has a normal operating range, a warning range, and an alert range. The machine will behave differently depending on its range. The objects behavior is delegated to NormalState, WarningState, and AlertState. I represent the difference in behavior with color schemes and text. The color schemes used are:

  1. Green - "Normal"
  2. Yellow - "Warning"
  3. Alert - "Alert"

Consider most operating machines; they have a normal, warning, and alert state. For example, a control system "machine" in a power plant such as a Nuclear, Fossil, or Combined Cycle Plant has normal operating ranges and ranges that would trigger an alarm. Operators and/or engineers might want to know the state of certain machines such as a transformer, boiler, etc. While the machine is in operation and running efficiently, it should be in a normal state. If something goes wrong a warning or alert should go off and the users should be alerted. This application demonstrates a simple way of achieving this via the State Pattern.

Class diagram

State - Abstract class

This class defines the interface for the derived classes:

using System;
using System.Drawing;

namespace StatePatternApp
{
    /// <span class="code-SummaryComment"><summary>
</span>

Transition class

I decided to move the transition logic from each state object to a transition class "Singleton". This allows the application to be more maintainable and scalable. The transition class has a Transform method that determines which state to transition to, if needed. *** Thanks to Marc Clifton for pointing out the redundancy of having the transition logic in each state object.

using System;

namespace StatePatternApp
{
    class Transition
    {
        private static Transition getInstance;
        protected Transition() {}

        
        public static Transition GetInstance()
        {
            if(getInstance == null)
            {
                getInstance = new Transition();
            }
            return getInstance;
        }

        public void Transform(State state)
        {
            if(state == null)
            {
                return;
            }

            // Get the type of state.
            string stateType = state.GetType().Name;

            // Are we in normal state?
            if(state.CurrentLevel < state.MaxDeviaton && 
                     state.CurrentLevel > state.MinDeviaton)
            {
                if(stateType.ToUpper() != "NORMALSTATE")
                {
                    state.ChangeState(state.Machine, 
                                 new NormalState(state));
                }
            }
            // Are we in warning?
            if(state.Deviation > 0)
            {
                if((state.CurrentLevel < state.MaxLevel && 
                      state.CurrentLevel >= state.MaxDeviaton) || 
                    state.CurrentLevel > state.MinLevel && 
                      state.CurrentLevel <= state.MinDeviaton)
                {
                    if(stateType.ToUpper() != "WARNINGSTATE")
                    {
                        state.ChangeState(state.Machine, 
                                     new WarningState(state));
                    }
                }
            }
            // Are we in alert state?
            if(state.CurrentLevel >= state.MaxLevel || 
                        state.CurrentLevel <= state.MinLevel)
            {
                if(stateType.ToUpper() != "ALERTSTATE")
                {
                    state.ChangeState(state.Machine, 
                                   new AlertState(state));
                }
            }
        }
    }
}

NormalState - derived state class

Implements a normal behavior. Displays Green and states "Normal":

using System;
using System.Drawing;

namespace StatePatternApp
{
    /// <span class="code-SummaryComment"><summary>
</span>

WarningState - derived state class

Implements a warning behavior. Displays Yellow and states "Warning":

using System;
using System.Drawing;

namespace StatePatternApp
{
    /// <span class="code-SummaryComment"><summary>
</span>

AlertState - derived state class

Implements an alert behavior. Displays Red and states "Alert":

using System;
using System.Drawing;

namespace StatePatternApp
{
    /// <span class="code-SummaryComment"><summary>
</span>

Machine class

This class maintains an instance of state:

using System;

namespace StatePatternApp
{
    /// <span class="code-SummaryComment"><summary>
</span>

Now that you have seen an example of the State Pattern, you may have probably realized many places where you can implement this. Although the State Pattern is very powerful, it can be overly complex in some situations and in such situations flags or polymorphism could be used instead. The State Pattern may have an initial impact upfront but is more maintainable and more productive over time.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Kenny Young
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

 
GeneralDifficult to understand Pin
Imtiaz.Ahmed25-May-11 9:59
memberImtiaz.Ahmed25-May-11 9:59 
GeneralI disagree with the Transition class Pin
Mark Graham19-Feb-09 3:16
memberMark Graham19-Feb-09 3:16 
Questioncould you help me to implement state pattern Pin
nallanch_srinivas26-Nov-07 10:49
membernallanch_srinivas26-Nov-07 10:49 
GeneralState in XML Pin
jdeer27-Jun-05 11:05
memberjdeer27-Jun-05 11:05 
GeneralRe: State in XML Pin
Kenny Young27-Jun-05 11:18
memberKenny Young27-Jun-05 11:18 
QuestionWhy is state logic is replicated? Pin
Marc Clifton24-Jun-05 3:20
protectorMarc Clifton24-Jun-05 3:20 
AnswerRe: Why is state logic is replicated? Pin
Kenny Young24-Jun-05 3:54
memberKenny Young24-Jun-05 3:54 
AnswerRe: Why is state logic is replicated? Pin
Kenny Young24-Jun-05 4:24
memberKenny Young24-Jun-05 4:24 
GeneralRe: Why is state logic is replicated? Pin
Marc Clifton24-Jun-05 5:01
protectorMarc Clifton24-Jun-05 5:01 
GeneralRe: Why is state logic is replicated? Pin
Kenny Young24-Jun-05 5:32
memberKenny Young24-Jun-05 5:32 
GeneralRe: Why is state logic is replicated? Pin
Marc Clifton24-Jun-05 6:10
protectorMarc Clifton24-Jun-05 6:10 
GeneralSeparation of concerns Pin
Marc Clifton23-Jun-05 16:43
protectorMarc Clifton23-Jun-05 16:43 
GeneralRe: Separation of concerns Pin
Kenny Young24-Jun-05 2:46
memberKenny Young24-Jun-05 2:46 
GeneralRe: Separation of concerns Pin
Marc Clifton24-Jun-05 3:10
protectorMarc Clifton24-Jun-05 3:10 
GeneralRe: Separation of concerns Pin
Kenny Young24-Jun-05 3:56
memberKenny Young24-Jun-05 3:56 
GeneralRe: Separation of concerns Pin
Marc Clifton24-Jun-05 4:47
protectorMarc Clifton24-Jun-05 4:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.160518.1 | Last Updated 23 Jun 2005
Article Copyright 2005 by Kenny Young
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid