• 15.状态模式(State)


    UML

    意图:允许一个对象在其内部状态改变时改变它的行为,使得对象看起来好像修改了它的类型一样。

    在这里插入图片描述

    Context:定义客户感兴趣的接口;
    维护一个ConcreteState子类的实例,这个实例定义当前的状态。
    State:定义一个接口来封装Context的与特定状态相关的行为。
    ConcreteState:每个ConcreteState实现一个与Context的一个状态相关的行为。

    状态模式是用途非常广泛的模式,所有使用到有限状态机(FSM)的地方都可以使用该模式。当然,如果不使用状态模式的话,switch/case语句也可以胜任简单的状态机,但对于大型的状态机具有大量的状态和事件,维护冗长、嵌套的switch/case语句是非常困难和容易出错的,而且switch/case语句通常都没有很好地分离状态机的逻辑和要执行的操作。另外一种选择状态转移表(WIS20中采用),它更容易维护,如果要增加新的状态转移,只要向表中增加一行就可以了,而且可以在运行时动态改变状态机的逻辑,还可以创建多个不同的状态转移表,在运行时动态地选择解释执行哪一个,但缺点是要编写大量的代码去支持状态转移表,而且需要查询和解释执行,速度较慢

    状态模式是最灵活、最高效的选择,因为它彻底分离了状态机的逻辑和动作行为,二者可以独立变化、互不影响,而且容易扩展,同时效率很高。当然,它也有缺点,就是编写State的派生类是一项乏味的工作,同时状态逻辑分散,无法在一个地方看到整个状态机的逻辑。为了克服这两个缺点,可以用一个文本描述状态转移表,然后用适当的Software Factory工具把它变成状态模式所必需的类的代码。

    GUI是典型的状态应用。哪些菜单项和按钮是Disabled,哪个窗口应该激活,焦点应放在哪里,等等,都和状态有关。如果不把这些要素组织成为一个单一的、集中的状态机控制结构,那将是一场噩梦。

    代码

    #include 
    #include 
    using namespace std;
     
     
    class State;
    class ConcreteStateA;
    class ConcreteStateB;
     
    class Context
    {
    public:
        State *state;
        Context(State *_state):state(_state){}
        void Request();
    };
     
    class State
    {
    public:
        string name;
        virtual void Handle(Context *c) = 0;
        virtual ~State(){
            cout << "delete :" << this->name << endl;
        };
    };
     
    class ConcreteStateA:public State
    {
    public:
        ConcreteStateA(){
            name = "状态A";
        }
        virtual void Handle(Context *c);
    };
     
    class ConcreteStateB:public State
    {
    public:
        ConcreteStateB(){
            name = "状态B";
        }
        virtual void Handle(Context *c);
    };
    void ConcreteStateA::Handle(Context *c){
        delete c->state;
        c->state = new ConcreteStateB();
    }
    void ConcreteStateB::Handle(Context *c){
        delete c->state;
        c->state = new ConcreteStateA();
    }
    void Context::Request(){
        cout << "当前状态:" << state->name << endl;
        this->state->Handle(this);
        cout << "切换后状态:" << state->name << endl << endl;
    }
    int main(void)
    {
        Context *c = new Context(new ConcreteStateA());
        c->Request();
        c->Request();
        c->Request();
        c->Request();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    运行结果

    当前状态:状态A
    delete :状态A
    切换后状态:状态B
     
    当前状态:状态B
    delete :状态B
    切换后状态:状态A
     
    当前状态:状态A
    delete :状态A
    切换后状态:状态B
     
    当前状态:状态B
    delete :状态B
    切换后状态:状态A
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    参考:https://lkmao.blog.csdn.net/article/details/129017715

  • 相关阅读:
    Java中的数组、Set、List、Map类型的互相转换总结
    ansible控制windows机器
    Linux xfs文件系统stat命令Birth字段为空的原因探究
    uni-app医院智能导诊系统源码
    k8s部署mysql一主两从
    redis基础数据结构
    极几何,本质矩阵,基础矩阵,单应矩阵
    缓存-多级缓存
    EventBus 一篇文章就够了
    NX二次开发UF_CAM_ask_doc_template_name 函数介绍
  • 原文地址:https://blog.csdn.net/qq_40178082/article/details/133039091