介绍
- 在通信网络中, TCP连接时用到的状态机就可以用该模式来实现, 即在当前系统有指定的集中状态且有如下的转换关系A–>B, B–>C, C–>D, D–>A, A–>D….., 上面的集中转换路线是在某些条件下才触发的, 这种情况就适合用状态机;
- 状态的切换不像普通的if else if else的应用, 对一些简单的条件判断或简单的状态切换是没有必要以增加子类的方法来处理的, 直接用if或switch就已经够了, 但对于很多实际应用, 往往状态之间的切换会有很多附带的东西的变化, 这个时候用状态机来封装这些变化,使得客户端不用取处理这些细节, 例如游戏世界天气系统可以分为 早上, 中午, 晚上, 深夜四种状态, 我们可以为每种状态下的游戏世界加入不同的天气, NPC…, 这里面可能会有大量要切换的信息, 如果部封装, 那么客户端可能就需要处理大量的细节.
- 在用状态机模式前, 客户端需要介入改变状态, 而状态的改变实现是复杂的;
- 在使用状态机后, 客户端可以直接使用Event实现, 根本不必关系该时间导致如何状态变化, 这些变化都将由状态机内部实现; 这是一种Event - condition - state, 状态模式封装了condition - state部分;
例子
- 现在依然以小梦和小明的故事来做例子:恋爱向来不是一帆风顺, 两个人磨合的过程难免会出现各种分歧, 因此吵架在所难免, 现在将吵架前后的几种状态变化列出:
A: 吵架前的甜蜜状态LoveState, B:出现分歧时的吵架状态QuarrelState, C:吵完后的冷静状态CalmdownState, D: 和好状态ForgiveState; 上面的四种状态,存在这样的转换过程:
- A–>B: have different opinion
- B–>C: no one compromise and have a stormy quarrelled
- C–>D: calmdown and forgive eachother
- C–>B: not figured and quarrelled again
- 每种状态下的心情是各不相同,
- A: sweet
- B: angry
- C: thinking
- D: guilt
代码
enum Scuess { NOTOK = 0, ISOK = 1, }; // 抽象状态 class State { public: virtual void feelling() = 0; virtual void DoForLove(FallInLove* love,const Scuess isok = ISOK) = 0; }; class ForgiveState : public State { public: virtual void feelling() { cout<<"xiaoming and xiaomeng forgave eachother"<<endl; } virtual void DoForLove(FallInLove* love,const Scuess isok = ISOK) { love->SetState( new LoveState); } }; class CalmdownState : public State { public: virtual void feelling() { cout<<"xiaoming and xiaomeng calmed down and thought about what's wrong"<<endl; } virtual void DoForLove(FallInLove* love,const Scuess isok = ISOK) { switch(isok) { case ISOK: love->SetState(new ForgiveState); break; case NOTOK: love->SetState(new QuarrelState); break; } } }; class QuarrelState : public State { public: virtual void feelling() { cout<<"xiaoming and xiaomeng feel angry"<<endl; } virtual void DoForLove(FallInLove* love,const Scuess isok = ISOK) { love->SetState(new CalmdownState); } }; class LoveState : public State { public: virtual void feelling() { cout<<"xiaoming and xiaomeng feel sweet"<<endl; } virtual void DoForLove(FallInLove* love,const Scuess isok = ISOK) { love->SetState(new QuarrelState); } }; class FallInLove { public: void SetState(State* st) { if(state) delete state; state = st; } void Lover( Scuess isok = ISOK) { state->feelling(); state->DoForLove(this, isok); } private: State* state; }; int main() { FallInLove* they = new FallInLove; they->SetState(new LoveState); they->Lover(); // 状态的切换 they->Lover(); they->Lover(NOTOK); they->Lover(NOTOK); they->Lover(ISOK); they->Lover(ISOK); they->Lover(); return 0; }