通过简单的十字专门的状态机,一步步从简单设计到运用设计原则和设计模式的实现。代码一步步抽象/重构,注释中详细说明了每一步抽象和重构的意义。代码可以拷贝编译完整运行。
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;
typedef enum
{
LOCKED,
UNLOCKED,
}State;
typedef enum
{
COIN,
PASS
}Event;
#if 0 //原始实现,一个类,switch/case实现状态切换,状态切换里面直接实现Action
class Turnstile
{
public:
int state = LOCKED;
void HandleEvent(Event event)
{
switch (state)
{
case LOCKED:
switch (event)
{
case COIN:
cout << "lock (event:coin)-> unlock" << endl;
state = UNLOCKED;
break;
case PASS:
cout << "Pass when locked, alarm!" << endl;
//state not change
break;
default:
break;
}
break;
case UNLOCKED:
switch (event)
{
case COIN:
cout << "unlock (event:coin)-> unlock" << endl;
//state not change
break;
case PASS:
cout << "unlock (event:pass)-> lock" << endl;
state = LOCKED;
break;
default:
break;
}
break;
default:
break;
}
}
};
int main(int argc, char** argv)
{
Turnstile turnstile;
turnstile.state = LOCKED;
turnstile.HandleEvent(PASS);
assert(turnstile.state == LOCKED);
turnstile.state = UNLOCKED;
turnstile.HandleEvent(PASS);
assert(turnstile.state == LOCKED);
}
#endif
#if 0//第一步抽象,把不易变的状态逻辑放在父类,Action提取出来。当有需求要求变更Action时,增加子类即可,符合开放封闭原则。但这种方式只对Action的改变符合OCP,对状态机结束状态的改变不符合OCP
class AbstractTurnstile
{
public:
int state = LOCKED;
virtual void Unlock() = 0;
virtual void Lock() = 0;
virtual void Alarm() = 0;
virtual void ThankYou() = 0;
void HandleEvent(Event event)
{
switch (state)
{
case LOCKED:
switch (event)
{
case COIN:
Unlock();
state = UNLOCKED;
break;
case PASS:
Alarm();
//state not change
break;
default:
break;
}
break;
case UNLOCKED:
switch (event)
{
case COIN:
ThankYou();
//state not change
break;
case PASS:
Lock();
state = LOCKED;
break;
default:
break;
}
break;
default:
break;
}
}
};
class ACustomerTurnstile : public AbstractTurnstile
{
virtual void Unlock() { cout << "lock (event:coin)-> unlock" << endl; }
virtual void Lock() { cout << "unlock (event:pass)-> lock" << endl; }
virtual void Alarm() { cout << "Pass when locked, alarm!" << endl; }
virtual void ThankYou() { cout << "unlock (event:coin)-> unlock" << endl; }
};
int main(int argc, char** argv)
{
AbstractTurnstile *pTurnstile = new ACustomerTurnstile;
pTurnstile->state = LOCKED;
pTurnstile->HandleEvent(PASS);
assert(pTurnstile->state == LOCKED);
pTurnstile->state = UNLOCKED;
pTurnstile->HandleEvent(PASS);
assert(pTurnstile->state == LOCKED);
delete pTurnstile;
}
#endif
#if 0//另一种抽象方式:不用继承而用聚合,把所有Action封装成一个TurnstileAction接口,作为父类指针传进Turnstile类中,状态切换时调用它。
//客户程序(main函数)中派生一个具体TurnstileAction类实现这四个接口
class TurnstileAction
{
public:
virtual void Unlock() = 0;
virtual void Lock() = 0;
virtual void Alarm() = 0;
virtual void ThankYou() = 0;
};
class Turnstile
{
public:
int state = LOCKED;
TurnstileAction* pAction = NULL;
Turnstile(TurnstileAction* pAct)
{
pAction = pAct;
}
void HandleEvent(Event event)
{
switch (state)
{
case LOCKED:
switch (event)
{
case COIN:
pAction->Unlock();
state = UNLOCKED;
break;
case PASS:
pAction->Alarm();
//state not change
break;
default:
break;
}
break;
case UNLOCKED:
switch (event)
{
case COIN:
pAction->ThankYou();
//state not change
break;
case PASS:
pAction->Lock();
state = LOCKED;
break;
default:
break;
}
break;
default:
break;
}
}
};
int main(int argc, char** argv)
{
//定义具体用户程序需要的Action
class ACustomerAction : public TurnstileAction
{
virtual void Unlock() { cout << "lock (event:coin)-> unlock" << endl; }
virtual void Lock() { cout << "unlock (event:pass)-> lock" << endl; }
virtual void Alarm() { cout << "Pass when locked, alarm!" << endl; }
virtual void ThankYou() { cout << "unlock (event:coin)-> unlock" << endl; }
};
//以此Action作为Turnstile的动作
ACustomerAction action;
Turnstile turnstile(&action);
//运行Turnstile
turnstile.state = LOCKED;
turnstile.HandleEvent(PASS);
assert(turnstile.state == LOCKED);
turnstile.state = UNLOCKED;
turnstile.HandleEvent(PASS);
assert(turnstile.state == LOCKED);
}
#endif
#if 0//第二步抽象,提取出状态迁移表,这样状态机的改变就只需要更改这个表和具体的TurnstileAction对象,不会更改原有框架代码,符合OCP
/*//第一步思路:直接Turnstile里面实现状态机逻辑和状态迁移表的建立
typedef void(*Action)();
class TurnstileAction
{
public:
static void Unlock() { cout << "lock (event:coin)-> unlock" << endl; }
static void Lock() { cout << "unlock (event:pass)-> lock" << endl; }
static void Alarm() { cout << "Pass when locked, alarm!" << endl; }
static void ThankYou() { cout << "unlock (event:coin)-> unlock" << endl; }
};
class Transition
{
public:
Transition(int inCurrentState, int inEvent, int inNewState, Action inAction) :
currentState(inCurrentState), event(inEvent), newState(inNewState), action(inAction)
{;}
int currentState;
int event;
int newState;
Action action;
};
class Turnstile
{
public:
int state = LOCKED;
vector<Transition> trans;
Turnstile()
{
//初始化时添加状态迁移表:当前状态,事件,新状态,动作
AddTransition(LOCKED, COIN, UNLOCKED, TurnstileAction::Unlock);
AddTransition(LOCKED, PASS, LOCKED, TurnstileAction::Alarm);
AddTransition(UNLOCKED, COIN, UNLOCKED, TurnstileAction::ThankYou);
AddTransition(UNLOCKED, PASS, LOCKED, TurnstileAction::Lock);
}
void HandleEvent(Event event)
{
for (unsigned int i = 0; i < trans.size(); i++)
{
Transition* pTrans = &(trans[i]);
if (state == pTrans->currentState && event == pTrans->event)
{
state = pTrans->newState;
pTrans->action();
}
}
}
private:
void AddTransition(int currentState, int event, int newState, Action action)
{
trans.push_back(Transition(currentState, event, newState, action));
}
};
*/
//重构:把不变的状态机逻辑抽象成父类,变化的部分(状态表建立,Action的具体实现)都拿出来子类中实现
//父类,不变的部分
typedef void(*Action)();
class Transition
{
public:
Transition(int inCurrentState, int inEvent, int inNewState, Action inAction) :
currentState(inCurrentState), event(inEvent), newState(inNewState), action(inAction)
{ ; }
int currentState;
int event;
int newState;
Action action;
};
class StateMachine
{
public:
int state;
vector<Transition> trans;
void HandleEvent(Event event)
{
for (unsigned int i = 0; i < trans.size(); i++)
{
Transition* pTrans = &(trans[i]);
if (state == pTrans->currentState && event == pTrans->event)
{
state = pTrans->newState;
pTrans->action();
}
}
}
protected:
void AddTransition(int currentState, int event, int newState, Action action)
{
trans.push_back(Transition(currentState, event, newState, action));
}
};
//子类,实现变化的部分
class Turnstile : public StateMachine
{
public:
//所有Action的具体实现
static void Unlock() { cout << "lock (event:coin)-> unlock" << endl; }
static void Lock() { cout << "unlock (event:pass)-> lock" << endl; }
static void Alarm() { cout << "Pass when locked, alarm!" << endl; }
static void ThankYou() { cout << "unlock (event:coin)-> unlock" << endl; }
//状态迁移表的建立
Turnstile()
{
//初始化时添加状态迁移表:当前状态,事件,新状态,动作
AddTransition(LOCKED, COIN, UNLOCKED, Unlock);
AddTransition(LOCKED, PASS, LOCKED, Alarm);
AddTransition(UNLOCKED, COIN, UNLOCKED, ThankYou);
AddTransition(UNLOCKED, PASS, LOCKED, Lock);
}
};
int main(int argc, char** argv)
{
//以此Action作为Turnstile的动作
Turnstile turnstile;
//运行Turnstile
turnstile.state = LOCKED;
turnstile.HandleEvent(PASS);
assert(turnstile.state == LOCKED);
turnstile.state = UNLOCKED;
turnstile.HandleEvent(PASS);
assert(turnstile.state == LOCKED);
}
#endif
#if 1/*状态模式实现,没啥作用,唯一的好处是把某个状态的所有行为放在一个具体的状态类中,一定程度上隔离了各状态的行为。
代价非常高昂:1.大量的派生类,2.逻辑分散,每增加或修改一个状态迁移,需要改所有的代码(State接口,具体State类,Turnstile类),非常难以修改/扩展/维护
以我的感觉和项目中遇到的2处状态机实现,STATE模式没什么吊用,状态迁移表才是最实用最有效的。
更悲剧的是,STATE模式用C++实现会有循环依赖问题!Turnstile和TurnstileLockedState之间循环依赖了,无法编译通过。还要搞点妖蛾子才能编译通过,
解除循环依赖编译问题参考http://zhidao.baidu.com/link?url=5jzADbx87CLFt_NihyAO79FwIFGFwDWW5VZsOgH-AU77ZdC-Hga5PgVlVkJiu7aVigim3LSuZ9EdSiTCB2Ul1_
或者用头文件方式http://www.cnblogs.com/wanggary/archive/2011/04/21/2024117.html和*/
class Turnstile;
class TurnstileState;
class TurnstileLockedState;
class TurnstileUnlockedState;
//抽象状态,定义一个状态,里面给出对所有事件的处理接口
class TurnstileState
{
public:
virtual void CoinEvent(Turnstile* pTs) = 0;
virtual void PassEvent(Turnstile* pTs) = 0;
};
//具体状态,定义各个具体状态及其对各种事件的处理。因为循环依赖的原因,不能直接在这里实现,在Turnstile类定义之后实现
class TurnstileLockedState : public TurnstileState
{
public:
virtual void CoinEvent(Turnstile* pTs);
virtual void PassEvent(Turnstile* pTs);
};
class TurnstileUnlockedState : public TurnstileState
{
public:
virtual void CoinEvent(Turnstile* pTs);
virtual void PassEvent(Turnstile* pTs);
};
//Context类,用于保存当前的状态和实现具体的状态切换和Action
class Turnstile
{
private:
TurnstileState* pState = NULL;
TurnstileLockedState lockedState;
TurnstileUnlockedState unlockedState;
public:
Turnstile()
{
pState = &lockedState;
}
void SetState(State state)
{//这里仍然用到了条件判断,可以重构成表形式
if (state == UNLOCKED)
{
pState = &unlockedState;
}
else
{
pState = &lockedState;
}
}
void CoinEvent()
{
pState->CoinEvent(this);
}
void PassEvent()
{
pState->PassEvent(this);
}
//Action函数,可以提出来用单独的一个TurnstileAction类来实现
void Unlock() { cout << "lock (event:coin)-> unlock" << endl; }
void Lock() { cout << "unlock (event:pass)-> lock" << endl; }
void Alarm() { cout << "Pass when locked, alarm!" << endl; }
void ThankYou() { cout << "unlock (event:coin)-> unlock" << endl; }
};
//具体状态类的实现,因为循环依赖的原因这里必须在Turnstile定义之后实现
void TurnstileLockedState::CoinEvent(Turnstile* pTs)
{
pTs->SetState(UNLOCKED);//状态切换
pTs->Unlock();//执行Action
}
void TurnstileLockedState::PassEvent(Turnstile* pTs)
{
//状态切换:空
pTs->Alarm();//执行Action
}
void TurnstileUnlockedState::CoinEvent(Turnstile* pTs)
{
//状态切换:空
pTs->ThankYou();//执行Action
}
void TurnstileUnlockedState::PassEvent(Turnstile* pTs)
{
pTs->SetState(LOCKED);//状态切换
pTs->Lock();//执行Action
}
int main(int argc, char** argv)
{
//以此Action作为Turnstile的动作
Turnstile turnstile;
//运行Turnstile
turnstile.SetState(LOCKED);
turnstile.PassEvent();
//assert(turnstile.state == LOCKED);
turnstile.CoinEvent();//to be unlocked
turnstile.PassEvent();//to be locked
//assert(turnstile.state == LOCKED);
}
#endif