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

    还是顺便练习一下.

  • 相关阅读:
    Spring 中的事务操作、注解、以及 XML 配置
    ..OBJLED.axf: Error: L6218E: Undefined symbol EXTI_Init (referred from exti.o). 错误修改
    ADC分辨率
    单片机ADC检测4-20mA电路,以及计算方法
    STM32速度---网页讲解
    转载电子发烧友网---STM32的IO口灌入电流和输出驱动电流
    精密电阻性能
    ..OBJCAN.axf: Error: L6411E: No compatible library exists with a definition of startup symbol __main.
    asp.net---jquery--ajax 实现滚动条滚动到底部分页显示
    柱状图dataLabels 文字格式 以及如何获取柱子的name(名称)属性
  • 原文地址:https://www.cnblogs.com/doulcl/p/10033824.html
Copyright © 2011-2022 走看看