zoukankan      html  css  js  c++  java
  • 关于状态机

    想把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;
    };

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

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

    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;运行结果:

    还是顺便练习一下.

  • 相关阅读:
    68
    56
    Django manager 命令笔记
    Django 执行 manage 命令方式
    Django 连接 Mysql (8.0.16) 失败
    Python django 安装 mysqlclient 失败
    H.264 SODB RBSP EBSP的区别
    FFmpeg—— Bitstream Filters 作用
    MySQL 远程连接问题 (Windows Server)
    MySQL 笔记
  • 原文地址:https://www.cnblogs.com/doulcl/p/10033824.html
Copyright © 2011-2022 走看看