Click here to Skip to main content
Click here to Skip to main content

Understanding State Pattern in C++

By , 25 Jun 2006
 

Introduction

State pattern is a behavioral type design pattern which is widely used in different applications especially in 3D-Graphics applications and applications for devices. In object oriented design, object can change its behavior based on its current state. A state pattern design implements state and behavior of an object. By using state pattern, we can reduce the complexity in handling different states of an object. This will help us to easily maintain code in future.

Legacy Method of Handling State of an Object

There are a lot of applications which need to maintain different states on different contexts. Mainly, it comes in the matter of 3D-Applications and devices. Without using state pattern, normally we are handling the state as follows:

class MyDevice
{
    int m_nCurrentState;

public:
    MyDevice()
    {
        m_nCurrentState= STATE_OFF;
    }
    // Function handling the state changes
    void HandleState();
};

void MyDevice::HandleState()
{
    /* changing state depends on the current state */
   if(STATE_OFF == m_nCurrentState)
   {
       m_nCurrentState = STATE_ON;
   }
   else if(STATE_ON == m_nCurrentState)
   {
       m_nCurrentState = STATE_ACQUIRING;
   }
   else if(STATE_ACQUIRING == m_nCurrentState)
   {
       m_nCurrentState = STATE_SAVE;
   }
  ....
  ....
  // We can add more states here
}

The problem with the above code is, usually the state changing and other activities will be centralized, so that the main function doing these activities will get complex and lengthy if there are many states are to be handled. This function will also get complex in the matter of maintainability. For handling few number of states, this approach is most suitable and easy to handle. The state pattern comes when complexity matters.

The Concept Behind the State Pattern

In state pattern, an object can have different states. Each state knows what its next state is. By using this architecture, we can add or remove a state at ease. This architecture mainly consists of 3 types of classes:

  1. Context Class: This class is the one which has the states. The application will be using (interfering with) this class. The class is responsible to maintain current state. 
  2. State Class: This is an abstract base class which can hold the different states (sub classes). The context class will be using this class pointer as its member to point the current state.
  3. Concentrate Class: This class implements the behavior of the state and behavior of the object.

Example: State Change

Here I’m taking the Sun as example: A person who is living in earth can view the sun in different states (even it remains constant). Those are morning, noon, afternoon, evening, night. For the sake of simplicity, I’m taking 3 states: Morning, Evening and Night.
The Sun starts (Initial state) with state Morning.
Morning knows that sun will move to Evening after its time period, Evening knows that beautiful Night will come after its turn and finally after a dark Night, it knows that Sun will change to a cool Morning. In this architecture, each state has a next state. When the object receives a command to change its state, it will ask the current state, what its next state is and modify itself to the new state returned.

Adding a New State

Suppose we want to add a new state Noon for Sun. We can do in simple steps as described below. Take Noon as an example:

  1. Define a new concentrate class (Noon class)
  2. Define its next state (Evening)
  3. Give this state as the next state of another state (change Morning’s next state from Evening to Noon).

Code

State Class

class CBaseState
{
public:
    // Pure virtual function
    virtual CBaseState* GetNextState() = 0;
    // print the string
    virtual    char* ToString() = 0;
};

Concentrate Classes

//////////////////////////////////////////////////////////////////////////
// State Morning
//////////////////////////////////////////////////////////////////////////
class CMorning : public CBaseState
{
public:
    virtual CBaseState* GetNextState();
    virtual    char* ToString();
};

//////////////////////////////////////////////////////////////////////////
// State Evening
//////////////////////////////////////////////////////////////////////////
class CEvening : public CBaseState
{
public:
    virtual CBaseState* GetNextState();
    virtual    char* ToString();
};

//////////////////////////////////////////////////////////////////////////
// State night
//////////////////////////////////////////////////////////////////////////
class CNight: public CBaseState
{
public:
    virtual CBaseState* GetNextState();
    virtual    char* ToString();
};

Context Class

//////////////////////////////////////////////////////////////////////////
// Context Class
//////////////////////////////////////////////////////////////////////////

class CSun
{
public:
    CSun();
    CSun(CBaseState* pContext /* Pass Allocated memory */);
    ~CSun();
    // Handles the next state
    void StateChanged();
    char* GetStateName();
protected:
    void DoCleanUp();
    // Pointer which holds the current state
    // Since this is and base class pointer
    // of Concentrate classes, it can holds their objects
    CBaseState* m_pState;
};

When State Change Request Comes

In the above example, the sun will be initialized to any of the states, for e.g., say morning.

CSun objSun(new CMorning);

If we need to change its current state to the next state, it is possible to do so by calling StateChanged interface provided by the context class.
See the sample code snippet for initializing and changing the state:

CSun objSun(new CMorning);
printf("\n\nSun Says Good %s !!!",objSun.GetStateName());
// inform that state has been changed
objSun.StateChanged();
printf("\n\nSun Says Good %s !!!",objSun.GetStateName());
// inform that state has been changed
objSun.StateChanged();
printf("\n\nSun Says Good %s !!!",objSun.GetStateName());
// inform that state has been changed
objSun.StateChanged();	
printf("\n\nSun Says Good %s !!!",objSun.GetStateName());

Inside the interface, the following things are happening:

// Handles the state change
void CSun::StateChanged()
{
    if (m_pState)
    {
        // Getting Next State
        CBaseState* pState = m_pState->GetNextState();
        // de allocates the memory
        delete m_pState;
          m_pState = pState;
    }
}

Defining Next State

Calling the GetNextState virtual function depends on the object. Each object will return its next state.

Morning object’s next state:

CBaseState* CMorning::GetNextState()
{
    return new CEvening;
}

Evening object’s next state:

CBaseState* CEvening::GetNextState()
{
    return new CNight;
}

Night object’s next state:

CBaseState* CNight::GetNextState()
{
    return new CMorning;
}

What About This Code

The above described code is a very basic level implementation of state Pattern. You can add more interfaces for your class to manage the state (e.g. setting and getting state) and improve the code with a good memory handling strategy.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sarath C
Technical Lead
India India
Member
Software Developer

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberArun S J18 Nov '12 - 16:45 
Simple
QuestionBad implementationmemberlboquillon8 Aug '11 - 13:04 
I think it's a bad implementation, each state must have the stimulus and return the appropriate state according to the stimulus received.
 
Example a car. If a car is off and the stimula is "run", the state changes to "running", and if the state is runnig and the stimula is "stop" the state changes to "stopped"Example a car. If a car is off and the stimula is run, the state changes to running, and if the state is runnig and the stimula is stop the state changes to stopped
 
Not sure if it compiles but it would be something like
 
class FSM {
private:
    class State {
    private:
        FSM* const fsm;
    public:
        virtual void run() const = 0;
        virtual voi stop() const = 0;
    };
 
    // stimuli are private because we want only accessible from the "State"
    // http://en.wikipedia.org/wiki/Dependency_inversion_principle
    class Stopped : public State {
    private:
        State* void run() {
            return fsm->state_running;
        }
        State* void stop() {
            return 0; // error or another state;
        }
    public:
        Stopped(FSM* f) : State (fsm) {}
    };
    class Running : public State {
    private:
        State* void run() {
            return 0; // error or another state
        }
        State* void stop() {
            return fsm->state_stopped;
        }
    public:
        Running(FSM* f) : State (fsm) {}
    }
    State* state_stopped;
    State* state_running;
    State* current;
 
public:
    FSM () {
        state_stopped = new Stopped (this);
        state_running = new Running (this);
    }
};
 
and the machine must have a method to stimulate
 
void stimulate (... ) { .... current = current-> (inser any stimulus here) }
GeneralState Pattern Example Codememberbenbrock266 Apr '09 - 3:39 
I can not download the code for your example. I tried to download code from the "Download source files - 3kb" link. After downloading, I get a StatePattern_src.zip zip file that is 0kb. Can you email the file's to my hotmail account or provide another means that I can download the src file's?
 

If you send the files to my hotmail account, you may have to rename the zip file to StatePattern_src.z, then I can rename the file when I download it to StatePattern_src.zip. The hotmail server may reject all zip file's.
 
Let me know if you want to send the files to my hotmail account. If so, I will send you my account.
 

Thanks,
 

Ben
GeneralRe: State Pattern Example CodememberDenWhin29 Apr '10 - 7:13 
Same problem here, file seems to be corrupt. If this could be fixed it would be appreciated, wouldn't mind a look at this.
GeneralRe: State Pattern Example CodememberSarath.29 Apr '10 - 17:43 
Thank you for the update. I fear, don't have the backup of this source. It's possible to recreate the source from the code snippet attached.
 
I will update this article soon with a better language and better code. Please wait for while and I'm sorry for the inconvenience.
-Sarath.
Rate the answers and close your posts if it's answered

GeneralRe: State Pattern Example Codememberfpersson.se10 Dec '11 - 1:21 
Ha, what a joke.... 20 months and nothing happens? The Code project is only fishing for new e-mail adress to spam :(
GeneralIssues.memberDealsBrokeMe8 Nov '06 - 11:21 
Did u think about optional transitions
 
The implementation will have issues due to painful mem allocs/deallocs.
==> Performance implications.
 
Imagine this: Can this states/transitions be configured/defined externally by user/developer? Thereby making this an engine?
GeneralGood Work !member*Dreamz3 Jul '06 - 19:45 

Good Work Sarath !!
Nice explanation for beginners...
GeneralRe: Good Work !memberSarath.4 Jul '06 - 3:03 
Thanks alot...
 
SaRath.

"It is your attitude, not your aptitude, that determines your altitude - Zig Ziglar."

My Blog | Understanding State Pattern in C++
Questionwhat about many conditional transitions ?memberlecerf11 Jun '06 - 22:22 
Hi,
 
Thank you for publishing this clearly understandable introduction to the state design pattern.
I would like to add two comments.
 
It may be good for beginners to insist that the object pattern is a description that structures the design through object collaboration but that does not imply exactly the same concrete realization. A state variable and a switch statement may be a good realization choice in some cases.
 
In your example each state has only one single mandatory transition. In the case where a state has many conditional transition, what would be the decision pattern be ? Will we use friend relations among states and there related object ? Could you continue your presentation with this kind of case ?
Thank you
 
LeCerf
AnswerRe: what about many conditional transitions ?memberSaRath C14 Jun '06 - 17:28 
Conditional transitions can be done inside the state change functions no?
 
In Erich Gamma's book he is saying that the transition can be done inside the state class and outside state class and also suggesting that handling inside the state class will be better.
 
SaRath.

"Don't Do Different things... Do Things Differently..."
 
Understanding State Pattern in C++
GeneralFSM designsmemberLeonti6 Jun '06 - 5:20 
Hi,
 
Nice intro to State pattern indeed; however, you should describe how state transitions occur. Without them, your Sun will never set Smile | :)
 
In software production lifecycle, this pattern suffers from many flaws. It does not solve maintenance issues, just like a switch statement it is replacing. If your software product has been around for many years (say 10+), your original FSM structure is likely to be modified by many different people. If your real-life FSM suffers from combinatorial state explosion, generating and maintaining dozens of state classes is no easy task. If your system has to keep thousands of objects, each having potentially dozens of states, this design becomes a memory and CPU hog. And I don't even count the number of transitions, which many authors recommend implementing as separate objects as well. Transitions usually invoke specific actions that change data in the system. This data has to be global to be available for all the transitions in the FSM. This causes maintenance issues too.
 
Bottom line: if you think it's as simple as this pattern may seem to imply, it ain't. There is a plethora of articles on how to solve issues decribed above, so if you set out to do it for your project, do your research first. Define what's important to you: memory footprint, speed, easy maintenance, extensibility, reusability, etc. Then use the design that fits your bill (and don't discount simple switch statement). Here are some references:
 
Sherif M. Yacoub; Hany H. Ammar, "Finite State Machine Patterns" - good classification of various FSM patterns.
 
JILLES VAN GURP & JAN BOSCH, "ON THE IMPLEMENTATION OF FINITE STATE MACHINES" - an attempt to solve maintenance issues.
 
Paul Dyson and Bruce Anderson, "State Patterns".
 
Paul Adamczyk, "The Anthology of the Finite State Machine Design Patterns".
 
Rijksuniversiteit Groningen, "ON THE DESIGN & PRESERVATION OF SOFTWARE SYSTEMS" - excellent thesis on many issues with software design, chapter 3 addresses shortcomings of the State pattern.
 
Best regards,
 
Leonti
 

 

GeneralRe: FSM designsmemberLeonti6 Jun '06 - 5:38 
Oops, the last reference should read:
 
Jilles van Gurp, "On the design & preservation of software systems", Ph. D. thesis, University of Groningen, February 2003.
 
Cheers,
 
Leonti

GeneralRe: FSM designsmemberSaRath C6 Jun '06 - 20:58 
Dear Leonti,
Thanks alot for your comment and Links provided.
I tried to explain the same in a common language that a novoice can understand that is why I classified this in a "Beginner" group.
 

Leonti wrote:
Nice intro to State pattern indeed; however, you should describe how state transitions occur. Without them, your Sun will never set

in the article i have explained, what will happen if a a state change occurs and the sample code provided as a zip demonstrating how to use the same. I'll add one more section, that how we can change the state of the "CSun" object. I dont that it is very difficult to understand from the artcile. I'll update it soon.
 

Leonti wrote:
In software production lifecycle, this pattern suffers from many flaws.

This patterns might have many advantages and disadvantages but what I tried is to explain an existing pattern with a simple example.
 

Leonti wrote:
Define what's important to you: memory footprint, speed, easy maintenance, extensibility, reusability, etc. Then use the design that fits your bill (and don't discount simple switch statement).

What u said is exactly correct. This pattern is trying to handle the states in object oriented way. So selecting whether we want to long switch statements or state classes will depends on our requirement.
 
Thanks alot for the link provided.
 
Once again thanks alot for a long informative feedback you have provided.
 
SaRath.

"Don't Do Different things... Do Things Differently..."
GeneralRe: FSM designsmemberDealsBrokeMe8 Nov '06 - 11:18 
Good intro to the pattern Sarath.
 
However, you said that this is an "OO" way of doing state changes.
 
Consider this, usually in protocols and places where u need FSM based designs,
U have paths describing valid transitions from 1 state to other.
Hence hard coding this in each class is very very difficult to maintain.
 
What we do is have a generic framework for FSM mgmt.
Then use a config file for development configured state changes
Otherwise we use a database based approach for user defined state changes.
 
All u need for either case is set of states [expandable]
Set of Valid transitions from one state to another.
Triggers that transition.
 
This is a very rudimentary workflow solution.
 
Hence this approach for implementing i don't think is either versatile or maintanable.
 
However i am partial to data driven architecture and similar engines.
 
Rajesh Kumar
-=-
GeneralCommentmemberjefito6 Jun '06 - 4:09 
This is a fairly simplistic approach, for a simplistic example. For example, you said:
 
"An object can have different states each state knows what its next state is. By using this architecture we can add or remove a state at ease."
 
But states do not always have a single next state, but often have a set of possible next states, the selection of which is determined by input to the machine. For example, morning, afternoon, evening and night are usually determined by time of day. How would you handle state change as determined by time changes in your architecture?
 
regards,
 
Jeff
GeneralRe: CommentmemberSaRath C6 Jun '06 - 21:08 
It can be handled inside the "StateChanged" interface by accpeint time as parameter and move to next state till it meet with the time.
 
I shall explain with some pseudo code
 
Define time span for each state (morning, noon, evening etc...) you may have to add a new interfaces to get and set time span in the state classes.
 
1. Get the time span of the current state.
2. Check whether current state's time span matching with the input specified
3. if no move to next next state by calling get next state and set it as current state go to step 1
4. if yes return;
 
Hope you clear
 
SaRath.

"Don't Do Different things... Do Things Differently..."
GeneralInteresting...memberJohn M. Drescher2 Jun '06 - 7:30 
I have done this dozens of times but never in a fully object oriented way. I set the state as a number and use a giant switch case to select the member function to call depending on what state the system is in...
 
John
GeneralRe: Interesting...memberSaRath C3 Jun '06 - 23:22 
Thanks for your complement.
We can implement this in "C" too...
it's really interesting. Sometimes I'll write one regarding same in "C"

 
SaRath.

"Don't Do Different things... Do Things Differently..."
GeneralWell donememberNicholas Butler2 Jun '06 - 6:33 
A good first article, you get my 5 Smile | :)
 
You obviously understand the subject - my favourite design pattern!
 
You could have emphasised the main benifit of the pattern a bit more though: the context class ( CSun ) changes it's behaviour depending on the current state.
 
For example, you could add a CanBarbeque method to your CSun class and show how this is called by its users Smile | :)
 
But overall it's a good introduction to the pattern - well done.
 
----------------------------
Be excellent to each other Smile | :)
 
EasiReports[^] My free reporting component for WinForms.
 
GeneralRe: Well donememberSaRath C3 Jun '06 - 23:23 
Thanx alot for your hearty comment.
 
SaRath.

"Don't Do Different things... Do Things Differently..."

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 25 Jun 2006
Article Copyright 2006 by Sarath C
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid