|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionState 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 objectThere are alot 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 followsclass 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 }What the problem with the above code is, usually the state changing and other activities will be centralized, so that the main function doing this 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 aproach is most suitable and easy to handle. The state pattern comes when complexity matters. The concept behind the state patternIn 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 2. State Class 3. Concentrate Class
Example: State ChangeHere I’m taking the Sun as example: A person who is living in earth can view sun in different states (even it remains constant). Those are morning, noon, afternoon, evening, night. For Simplicity I’m taking 3 states Morning, Evening and Night.The Sun is starting (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 StateSuppose we want to add a new state Noon for Sun. We can do in simple steps as described below. Take Noon as example1. 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 classclass CBaseState
{
public:
// Pure virtual function
virtual CBaseState* GetNextState() = 0;
// print the string
virtual char* ToString() = 0;
};
Concetrate 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 ComesIn 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 next state, it is possible to by calling StateChanged interface proveided by the context class.
See 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 StateOn calling the GetNextState virtual function depends on the object each object will return its 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 codeThe 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.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||