Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

State

0.00/5 (No votes)
3 Oct 2008 1  
StateThe State pattern allows an object to change it behaviour when its internal state changes. The pattern is a type of behavioral design

This articles was originally at wiki.asp.net but has now been given a new home on CodeProject. Editing rights for this article has been set at Bronze or above, so please go in and edit and update this article to keep it fresh and relevant.

State

The State pattern allows an object to change it behaviour when its internal state changes.

The pattern is a type of behavioral design pattern, and is also known as the objects for states pattern. This pattern is used in programming to represent the state of an object. This is a way for an object to partially change its type at runtime

A VB example of the State Pattern

This example shows the different states a person would go through after drinking beer, a bit crude but I hope it demostrates what the state pattern is.

The below code gives this output:

I have had 0 cans of beer and I am feeling sober.
*hic* I have had 6 cans of beer and I am feeling a bit tipsy :0).
*hic* I have had 14 cans of beer and I am feeling a very, very drunk :0).

Dim aPerson As New Person
Response.Write(
String.Format("{0}<br/>", aPerson.DrunkState.displayState))
' Have a beer
aPerson.Drink(6)
Response.Write(
String.Format("{0}<br/>", aPerson.DrunkState.displayState))
' Have some more beers
aPerson.Drink(3)
aPerson.Drink(5)
Response.Write(
String.Format("{0}<br/>", aPerson.DrunkState.displayState))

' Person object
Public Class Person        

       Private
_CansOfBeerDrunk As Integer = 0
      
' The state of the person
      
Private _DrunkState As DrunkState

       Public Sub New()
          
' Default state is sober
          
_DrunkState = New Sober(0, Me)
      
End Sub

       Public Sub Drink(ByVal numberOfCans As Integer)
           _CansOfBeerDrunk += numberOfCans
           
           _DrunkState.AmountDrunk(_CansOfBeerDrunk)
      
End Sub

       Public Property DrunkState() As DrunkState
          
Get
              
Return _DrunkState
          
End Get
           
Set(ByVal value As DrunkState)
               _DrunkState = value
          
End Set
      
End Property
End Class

' Abstract Base State Class
Public MustInherit Class DrunkState

      
Protected _person As Person
      
Protected _numberOfCans As Integer       

       MustOverride
Sub AmountDrunk(ByVal NumberOfCans As Integer)

       MustOverride Function displayState() As String

       Public ReadOnly Property NumberOfCansDrunk() As Integer
          
Get
              
Return _numberOfCans
          
End Get
       
End Property

       Public ReadOnly Property Person() As Person
          
Get
              
Return _person
          
End Get
      
End Property

End Class

' Sober State
Public Class Sober
       
Inherits DrunkState

       Public Sub New(ByVal State As DrunkState)
          
Me._numberOfCans = State.NumberOfCansDrunk

          
Me._person = State.Person
       
End Sub

       Public Sub New(ByVal NumberOfCans As Integer, ByVal aPerson As Person)
          
Me._numberOfCans = NumberOfCans

           Me._person = aPerson
      
End Sub

       Public Overrides Sub AmountDrunk(ByVal NumberOfCans As Integer)
          _numberOfCans = NumberOfCans

         
CheckOnStateOfPerson()
      
End Sub

       Private Sub CheckOnStateOfPerson()
         
' Check to see if the number of cans will change our persons
         
' state
         
If Me._numberOfCans > 5 Then
              
_person.DrunkState = New Tipsy(Me)
          
ElseIf Me._numberOfCans > 10 Then
              
_person.DrunkState = New DrunkAsASkunk(Me)
         
End If
      
End Sub

       Public Overrides Function displayState() As String
        
Return String.Format("I have had {0} cans of beer and I am feeling sober.", Me._numberOfCans)
      
End Function
End Class

' Tipsy State
Public Class Tipsy
      
Inherits DrunkState

      Public Sub New(ByVal State As DrunkState)
        
Me._numberOfCans = State.NumberOfCansDrunk

        
Me._person = State.Person
     
End Sub

      Public Sub New(ByVal NumberOfCans As Integer, ByVal aPerson As Person)
        
Me._numberOfCans = NumberOfCans

         Me._person = aPerson
     
End Sub

      Public Overrides Sub AmountDrunk(ByVal NumberOfCans As Integer)
        
Me._numberOfCans = NumberOfCans
        
CheckOnStateOfPerson()
     
End Sub

      Private Sub CheckOnStateOfPerson()
       
' Check to see if the number of cans will change our persons
       
' state
       
If Me._numberOfCans < 5 Then
           
Me._person.DrunkState = New Sober(Me)
       
ElseIf Me._numberOfCans > 10 Then
           
Me._person.DrunkState = New DrunkAsASkunk(Me)
       
End If
     
End Sub

      Public Overrides Function displayState() As String
        
Return String.Format("*hic* I have had {0} cans of beer and I am feeling a bit tipsy :0).", Me._numberOfCans)
     
End Function
End Class

' Very Drunk State
Public Class DrunkAsASkunk
     
Inherits DrunkState

      Public Sub New(ByVal State As DrunkState)
         
Me._numberOfCans = State.NumberOfCansDrunk
        
Me._person = State.Person
     
End Sub

      Public Sub New(ByVal NumberOfCans As Integer, ByVal aPerson As Person)
        
Me._numberOfCans = NumberOfCans

        
Me._person = aPerson
     
End Sub

      Public Overrides Sub AmountDrunk(ByVal NumberOfCans As Integer)
       
Me._numberOfCans = NumberOfCans

       
CheckOnStateOfPerson()
     
End Sub

      Public Overrides Function displayState() As String
        
Return String.Format("*hic* I have had {0} cans of beer and I am feeling a very, very drunk :0).", Me._numberOfCans)
     
End Function

      Private Sub CheckOnStateOfPerson()
       
' Check to see if the number of cans will change our persons
       
' state
       
If Me._numberOfCans < 5 Then
           
Me._person.DrunkState = New Sober(Me)
       
ElseIf Me._numberOfCans < 10 Then
           
Me._person.DrunkState = New Tipsy(Me)
       
End If
     
End Sub
End Class
A C# example of the State Pattern

    #region State

    public interface IState

    {

        void Handle(StateContext context);

    }

    #endregion

    #region Context
 

    public class StateContext

    {

        #region Properties

        /// <summary>

        /// The current inner state

        /// </summary>

        public IState State { get; set; }

        /// <summary>

        /// An inner counter of this context

        /// </summary>

        public int Counter { get; set; }

        #endregion

        #region Ctor

        /// <summary>

        /// Construct a new StateContext with the

        /// given first state

        /// </summary>

        /// <param name="state">The first state of the object</param>

        public StateContext(IState state)

        {

            State = state;

        }

        #endregion

        #region Methods

        /// <summary>

        /// Send a request to be handled by the inner state

        /// behavior

        /// </summary>

        public void Request()

        {

            State.Handle(this);

        }

        #endregion

    }

    #endregion

    #region Concrete State

    public class ConcreteStateA : IState

    {

        #region IState Members

        public void Handle(StateContext context)

        {

            context.Counter += 2;

            // change the context state to a new state

            context.State = new ConcreteStateB();

        }

        #endregion

    }

    public class ConcreteStateB : IState

    {

        #region IState Members

        public void Handle(StateContext context)

        {

            context.Counter -= 1;

            // change the context state to a new state

            context.State = new ConcreteStateA();

        }

        #endregion

    }

    #endregion

The implementation of state depends on inheritance. The main issues is to
understand that every concrete state is responsible to change the current 
context behavior to the next context behavior in the chain of behaviors. The
example I gave is simple and can be run with this code:

   // initialize a context with a first state behavior

   StateContext context =

      new StateContext(new ConcreteStateA());

   context.Request();

   Console.WriteLine("The current counter need to be 2: {0}",

      context.Counter);

   context.Request();

   Console.WriteLine("The current counter need to be 1: {0}",

      context.Counter);

   context.Request();

   Console.WriteLine("The current counter need to be 3: {0}",

      context.Counter);

   Console.Read();


Articles

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