关于状态机

想把c++的设计模式写完,就从状态机开始吧

状态机起源于我们在不同的状态下去做不同或相同的事情,会得到不同的结果

当然,这样是最直接的

switch(state)

case State1:

  dosomething..

case State2:

      dosomething..

......

这样是一定能把所有case写完的,就像计算器起源于0和1一样简单

但我们在实际工作中却不会这么做,主要是这么做扩展性不强,随着case增多,state1到state2到state3等等之间存在茫茫多的联系,在不同state下将产生越来越多的判断,最终写着写着就崩溃了。

c++用状态机去控制它们,要构建这样一个状态机,需要两个元素,一个是controller,控制状态的切换,统一管理这些状态,另外就是状态

设想这样的一个状态机,主体是人(controller),拥有3个健康状态 :

typedef enum
{
    health ,
    sub_health,
    hopeless
} PERSON_STATE_ID;

这个人有三个爱好:

typedef enum
{
    run = 0,
    work,
    latesleep
} PERSON_FAN;

这个人的类的构建:

class State;
class healthState;
class sub_healthState;
class hopelessState;

class Person
{
public:
    Person(string name);

    ~Person();
    void gotohealth();
    void gotoSubHealth();
    void gotoHopeless();
    State* getCurrentState();
    void setCurrentState(State * state);
    State* getCurrentStatebyId(PERSON_STATE_ID id);
    void init();
private:
    string mName;
    State * m_CurrentState;
    healthState * mhealthState;
    sub_healthState * msub_healthState;
    hopelessState * mhopelessState;
};

它的数据成员有一个名字,一个当前状态的指针,指向健康状态的指针,指向非健康状态的指针和指向接近天堂的指针。

接着构建健康三种状态的基类。

class State
{
public:
    State(Person * Per):P_person(Per),mStateNum(health){};
    virtual void behavior(PERSON_FAN num)= 0;
    virtual void into()
    {
        cout<<"now state is: "<< getstateStringbyId(mStateNum).c_str()<< endl <<endl;
    };
    string getstateStringbyId(PERSON_STATE_ID Num)
    {
        switch(Num)
        {
            case health: return  "health";
            case sub_health: return "not health";
            case hopeless:   return "can not save yourself!";
        }
    }
    Person* obtainPersonObject()  const { return P_person; };
    PERSON_STATE_ID getStateNum() const {return mStateNum;};
    void setStateNum(PERSON_STATE_ID stateId) {mStateNum = stateId;};
     virtual ~State(){};
private:
    Person * P_person;
    PERSON_STATE_ID mStateNum;
};

基类state拥有一个controller,即指向这个人的指针,和一个标记此时状态的数字id,另外做了一个纯虚函数去让不同状态进行切换,做几个也可以,这个不限

几个基本健康状态的类,当这个人在健康时,如果天天work,就会进入sub_health,如果天天 latesleep,就会进入hopeless的状态,而如果在hopeless的状态,天天run也只能进入sub_health的状态

class healthState : public State
{
public:
    healthState(Person* mPerson): State(mPerson){};
    ~healthState(){};
    void behavior(PERSON_FAN num)
    {
        switch(num)
        {
            case run:
            {}
            break;
            case work:
            {
                obtainPersonObject()->gotoSubHealth();
            }
            break;
            case latesleep:
            {
                obtainPersonObject()->gotoHopeless();
            }
            break;
            default:
            break;
        }
    }
    void into()
    {
        setStateNum(health);
        State::into();
    }
};

class sub_healthState : public State
{
public:
    sub_healthState(Person* mPerson): State(mPerson){};
    ~sub_healthState(){};
    void behavior(PERSON_FAN num)
    {
        switch(num)
        {
            case run:
            {
               obtainPersonObject()->gotohealth();
            }
            case work:
            {
                //do nothing;
            }
            break;
            case latesleep:
            {
                obtainPersonObject()->gotoHopeless();
            }
            break;
            default:
            break;
        }
    }
    void into()
    {
        setStateNum(sub_health);
        State::into();
    }
};

class hopelessState : public State
{
public:
    hopelessState(Person* mPerson):State(mPerson){};
    ~hopelessState(){};
    void behavior(PERSON_FAN num)
    {
        switch(num)
        {
            case run:
            {
                obtainPersonObject()->gotoSubHealth();
            }
            break;
            case work:
            case latesleep:
            {
                //do nothing;
            }
            break;
            default:
            break;
        }
    }
    void into()
    {
        setStateNum(hopeless);
        State::into();
    }
};

人这个controller的具体实现:

Person::Person(string name):mName(name)
    {
        init();
    };
    Person::~Person()
    {
        delete mhealthState;
        delete msub_healthState;
        delete mhopelessState;
    };
    void Person::gotohealth()
    {
        mhealthState->into();
        setCurrentState(mhealthState);
    };
    void Person::gotoSubHealth()
    {
        msub_healthState->into();
        setCurrentState(msub_healthState);
    };
    void Person::gotoHopeless()
    {
        mhopelessState->into();
        setCurrentState(mhopelessState);
    };
    State *Person::getCurrentState()
    {
        return m_CurrentState;
    };
    void Person::setCurrentState(State * state)
    {
        m_CurrentState = state;
    };
    void Person::init()
    {
        mhealthState = new healthState(this);
        msub_healthState = new sub_healthState(this);
        mhopelessState = new hopelessState(this);
        m_CurrentState = mhealthState;
    };

状态的迁移实际是通过m_CurrentState这个指针来完成的,当然基于C++那个封装的特性,这么写肯定是不行的,声明和实现得分开到.cpp和.h中,我这么写只为编过

void main()
{
    Person mperson("common");
    int a;
    cout<<"please input your favorite id(0: run; 1: work; 2: latesleep):"<<endl;
    while(cin>>a)
    {
        mperson.getCurrentState()->behavior(PERSON_FAN(a));
        cout<<"please input your favorite id(0: run; 1: work; 2: latesleep):"<<endl;
    }
}

主函数入口,前面省略了几个基本头文件和不推荐使用的using namespace std;运行结果:

前人写好了模板,我大概只是在模仿,主要还是顺便练习一下,个人理解。

猜你喜欢

转载自www.cnblogs.com/doulcl/p/10033824.html