Difference between revisions of "State"
(→Code Samples) |
(→Greeting Message Generator) |
||
Line 50: | Line 50: | ||
}; | }; | ||
</pre> | </pre> | ||
− | |||
'''Concrete class definitions''' | '''Concrete class definitions''' | ||
<pre> | <pre> | ||
Line 59: | Line 58: | ||
virtual char* ToString(); | virtual char* ToString(); | ||
}; | }; | ||
− | |||
class CEvening : public CBaseState{ | class CEvening : public CBaseState{ | ||
public: | public: | ||
Line 71: | Line 69: | ||
virtual char* ToString(); | virtual char* ToString(); | ||
}; | }; | ||
− | |||
</pre> | </pre> | ||
'''Context class structure''' | '''Context class structure''' | ||
Line 97: | Line 94: | ||
} | } | ||
</pre> | </pre> | ||
− | |||
− | |||
− | |||
− | |||
'''Code that changes state''' | '''Code that changes state''' | ||
<pre> | <pre> |
Revision as of 09:52, 23 March 2007
Contents
Description
What is the State Pattern?
- Allow to sub-divide the behavior of an object depending on its current state.
- Classified as a behavior pattern.
- Also known as Objects for States.
When do you use the State Pattern?
Suppose that you are playing War Craft. Your units will behave according to your commands. For example, if the "Attack" command is given to your units, the state of the units will be changed to "Attack State" and they will attack the enemies around them. If you set them to hold their position, their state will be changed to "Hold Position" and your units will stop attacking and stand around. These behaviors such as "attack" behavior and "hold position" behavior can be also applied to other species – there are five species in this game; undeads, orcs, night elves, humans and corrupted night elves. By the use of the state pattern, it is possible to save time and gain reusability and maintainability since you do not have to code the similar unit behaviors all over again for other species when programming such game.
Advantages of using State Pattern
1. State pattern allows object to perform state-specific behaviors and operations and partitions behavior based on its state.
State pattern is beneficial since the object's state-specific behaviors are maintained in a single object. It is much easier to create and add new states and transitions than extending behaviors using if or switch statements. New state implements the state interface, and new state can extend other states.
2. State pattern makes state transition explicit.
If the state is defined with an internal data values, its state transition do not have explicit representation. If a variable is used to specify its current state, it will be difficult to extend and maintain since the states and transitions are handled using many if and switch statements.
3. State objects can be shared by other classes.
As mentioned above, state object can be used by other classes. For example, all five species of the War Craft have common behaviors such as "Attack" and "Hold Position" behaviors, and those state-specified behaviors can be used by all character classes. Click the link below to see the examples.
UML Diagram
State Pattern UML Diagram
Code Samples
Greeting Message Generator
Click here to see the UML diagram for this example
State class interface definition
class CBaseState { public: virtual CBaseState* GetNextState() = 0; virtual char* ToString() = 0; };
Concrete class definitions
class CMorning : public CBaseState{ public: virtual CBaseState* GetNextState(); virtual char* ToString(); }; class CEvening : public CBaseState{ public: virtual CBaseState* GetNextState(); virtual char* ToString(); }; class CNight: public CBaseState{ public: virtual CBaseState* GetNextState(); virtual char* ToString(); };
Context class structure
class CSun{ public: CSun(); CSun(CBaseState* pContext); ~CSun(); void StateChanged(); char* GetStateName(); protected: void DoCleanUp(); CBaseState* m_pState; };
Function definition for state change
void CSun::StateChanged(){ if (m_pState){ CBaseState* pState = m_pState->GetNextState(); delete m_pState; m_pState = pState; } }
Code that changes state
CBaseState* CMorning::GetNextState(){return new CEvening;} CBaseState* CEvening::GetNextState(){return new CNight;} CBaseState* CNight::GetNextState(){return new CMorning;}
Simple example of actual implementation
CSun objSun(new CMorning); printf("\n\nSun Says Good %s !!!",objSun.GetStateName()); objSun.StateChanged(); printf("\n\nSun Says Good %s !!!",objSun.GetStateName()); objSun.StateChanged(); printf("\n\nSun Says Good %s !!!",objSun.GetStateName()); objSun.StateChanged(); printf("\n\nSun Says Good %s !!!",objSun.GetStateName());
Game programming: Character Status
Click here to see the UML diagram for this example
Header File Content
class IState; class cDarkElf : public cUnit { IState* _pState; void ChangeState(IState*); public: cDarkElf(); ~cDarkElf(); void Attack(cUnit* Target); void Move(int x, int y); void Stop(); void HoldPosition(); void Slaughter(cUnit* Target); void Update(); };
Class Definitions for State objects
class IState { const ID_STATE _ID; public: enum ID_STATE {STATE_ATTACK, STATE_MOVE, STATE_STOP, STATE_HOLDPOSITION, STATE_SLAUGHTER}; IState(ID_STATE state) : _ID(state) {} ID_STATE GetID() {return _ID;} virtual void Operate() = 0; }; class cState_Attack : public IState { cUnit* _pTarget; cUnit* _pUnit; public: cState_Attack(cUnit* target, cUnit* pUnit) : IState(STATE_ATTACK), _pTarget(target), _pUnit(pUnit){} void Operate(); }; class cState_Move : public IState { int _x, _y; cUnit* _pUnit; public: cState_Move(int x, int y, cUnit* pUnit); void Operate(); }; class cState_Stop : public IState { public: void Operate(); }; class cState_HoldPosition : public IState { public: void Operate(); }; class cState_SLAUGHTER : public IState { cUnit* _pTarget; cUnit* _pUnit; public: cState_Slaughter(cUnit* target, cUnit* pUnit) : IState(STATE_SLAUGHTER), _pTarget(target), _pUnit(pUnit) {} void Operate(); };
Class Functions
cDarkElf::cDarkElf() {_pState = new cState_Stop;} cDarkElf::~cDarkElf() {delete _pState;} void cDarkElf::ChangeState(IState* pState) { delete _pState; _pState = pState; } void cDarkElf::Attack(cUnit* Target) { ChangeState(new cState_Attack(Target, this)); } void cDarkElf::Move(int x, int y) { ChangeState(new cState_Move(x, y, this)); } void cDarkElf::Stop() { ChangeState(new cState_Stop); } void cDarkElf::HoldPosition() { ChangeState(new cState_HoldPosition); } void cDarkElf::Patrol(int x1, int y1, int x2, int y2) { ChangeState(new cState_Patrol(x1, y1, x2, y2)); } void cDarkElf::Update() { _pState->Operate(); }
References
- Erich, Gamma. Design Patterns : elements of reusable object-oriented software. Upper Saddle River: Pearson Education Corporate Sales Division, 2000.
- "4th Lecture about Design Patterns". Ssamdark's Homepage. March 20, 2007 <http://www.misofruit.co.kr/seojewoo/programming/designpattern4.htm>.