设计模式 c++版(19)—— 状态模式

定义:
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。(状态的变更引起了行为的变更,从外部看起来好像这个对象对应的类发生了改变一样)


示例一:状态模式(通用版)


1. 类图 26-5

 

2. 类图说明

State 抽象状态角色
接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。

ConcreteState 具体状态角色
每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,即本状态要做的事情,以及本状态如何过度到其他状态。

Context 环境角色
定义客户端需要的接口,并且负责具体状态的切换。

 


3. 代码清单
 

#include <QCoreApplication>
#include <QDebug>

class Context;
//抽象环境角色
class State
{
public:
    void    setContext(Context &context)
    {
        this->m_context = &context;
    }
    virtual void    handle1()   = 0;
    virtual void    handle2()   = 0;

protected:
    Context *m_context;
};

//具体环境角色
class Context
{
public:
    State*  getCurrentState()
    {
        return this->m_curState;
    }
    void    setCurrentState(State* state)
    {
        this->m_curState = state;
        this->m_curState->setContext(*this);
    }
    void    handle1()
    {
        this->m_curState->handle1();
    }
    void    handle2()
    {
        this->m_curState->handle2();
    }

public:
    static State* m_state1;
    static State* m_state2;
private:
    State*  m_curState;
};

//环境角色
class State1:public State
{
public:
    virtual void    handle1()
    {
        qDebug() << "this is handle1";
    }
    virtual void    handle2()
    {
        this->m_context->setCurrentState(this->m_context->m_state2);
        this->m_context->handle2();
    }
};

class State2:public State
{
public:
    virtual void    handle1()
    {
        this->m_context->setCurrentState(this->m_context->m_state1);
        this->m_context->handle1();
    }
    virtual void    handle2()
    {
        qDebug() << "this is handle2";
    }
};

State* Context::m_state1 = new State1();
State* Context::m_state2 = new State2();

int main()
{
    Context context;
    State* state1 = new State1();
    context.setCurrentState(state1);
    context.handle1();
    context.handle2();
    
    delete state1;
    
    return 0;
}

 


示例二:电梯

1. 类图 26-1

 

2. 分析特定状态

  •  敞门状态。这时可以关门
  •  闭门状态。这时可以开门,停止,运行
  •  运行状态。这时只能停止
  •  停止状态。这时可以运行和开门

 

3. 电梯状态和动作之间关系图 26-2

 

4. 扩展状态后的类图 26-3

 

5. 扩展状态后代码
 


//电梯接口
class ILift
{
public:
    virtual void    open()  = 0;
    virtual void    close() = 0;
    virtual void    run()   = 0;
    virtual void    stop()  = 0;
    virtual void    setState(int state)  = 0;
    
public:
    static const int OPENING_STATE  = 1;
    static const int CLOSING_STATE  = 2;
    static const int RUNNING_STATE  = 3;
    static const int STOPPING_STATE = 4;
};

//电梯实现
class Lift:public ILift
{
public:
    virtual void    open()
    {
        switch(this->m_state)
        {
        case OPENING_STATE:
            break;
        case CLOSING_STATE:
            this->openWithoutLogic();
            this->setState(OPENING_STATE);
            break;
        case RUNNING_STATE:
            break;
        case STOPPING_STATE:
            this->openWithoutLogic();
            this->setState(OPENING_STATE);
            break;
        }  
    }
    virtual void    close()
    {
        switch(this->m_state)
        {
        case OPENING_STATE:
            this->closeWithoutLogic();
            this->setState(CLOSING_STATE);
            break;
        case CLOSING_STATE:
            break;
        case RUNNING_STATE:
            break;
        case STOPPING_STATE:
            break;
        }  
    }
    virtual void    run()
    {
        switch(this->m_state)
        {
        case OPENING_STATE:
            break;
        case CLOSING_STATE:
            this->runWithoutLogic();
            this->setState(RUNNING_STATE);
            break;
        case RUNNING_STATE:
            break;
        case STOPPING_STATE:
            this->runWithoutLogic();
            this->setState(RUNNING_STATE);
            break;
        } 
    }
    virtual void    stop()
    {
        switch(this->m_state)
        {
        case OPENING_STATE:
            break;
        case CLOSING_STATE:
            this->stopWithoutLogic();
            this->setState(CLOSING_STATE);
            break;
        case RUNNING_STATE:
            this->stopWithoutLogic();
            this->setState(CLOSING_STATE);
            break;
        case STOPPING_STATE:
            break;
        }  
    }
    virtual void    setState(int state)
    {
        this->m_state = state;
    }
    
private:
    void    closeWithoutLogic()
    {
        qDebug() << "close";
    }
    void    openWithoutLogic()
    {
        qDebug() << "open";
    }
    void    runWithoutLogic()
    {
        qDebug() << "run";
    }
    void    stopWithoutLogic()
    {
        qDebug() << "stop";
    }

private:
    int     m_state;
};

int main()
{
    ILift *lift = new Lift();
    lift->setState(ILift::STOPPING_STATE);
    lift->open();
    lift->close();
    lift->run();
    lift->stop();
    
    delete lift;
    return 0;
}

 

6. 存在的问题

 电梯实现类Lift有点长。里面使用了大量的switch...case,在业务复杂的情况下,程序会更长。
 扩展性非常差。电梯还有通电和断点两个状态,若要增加这两个方法,原有4个方法都需要增加判断条件
 非常规状态无法实现。

 

7. 使用状态模式,类图 26-4

8. 使用状态模式,代码

/ ******************************************* 声明 ********************************* ///

class LiftState;
//上下文类  声明
class Context
{
public:
    Context();
    LiftState*  getLiftState();
    void        setLiftState(LiftState *liftState);
    void        open();
    void        close();
    void        run();
    void        stop();
    
public:
    static LiftState *m_openningState;
    static LiftState *m_closingState;
    static LiftState *m_runningState;
    static LiftState *m_stoppingState;
    
private:
    LiftState *m_liftState;
};

//抽象电梯状态 声明
class LiftState
{
public:
    void            setContext(Context &context);
    virtual void    open()  = 0;
    virtual void    close() = 0;
    virtual void    run()   = 0;
    virtual void    stop()  = 0;

protected:
    Context *m_context;
};

//关闭状态 声明
class ClosingState:public LiftState
{
public:
    virtual void    open();
    virtual void    close();
    virtual void    run();
    virtual void    stop();
};

//敞门状态 声明
class OpenningState:public LiftState
{
public:
    virtual void    open();
    virtual void    close();
    virtual void    run();
    virtual void    stop();
};

//运行状态 声明
class RunningState:public LiftState
{
public:
    virtual void    open();
    virtual void    close();
    virtual void    run();
    virtual void    stop();
};

//停止状态 声明
class StoppingState:public LiftState
{
public:
    virtual void    open();
    virtual void    close();
    virtual void    run();
    virtual void    stop();
};

/// *********************************************** 定义 ************************************************* ///

//上下文类  定义
LiftState* Context::m_openningState = new OpenningState();
LiftState* Context::m_closingState = new ClosingState();
LiftState* Context::m_runningState = new RunningState();
LiftState* Context::m_stoppingState = new StoppingState();

Context::Context()
{
    this->setLiftState(this->m_closingState);
}

LiftState* Context::getLiftState()
{
    return this->m_liftState;
}
void    Context::setLiftState(LiftState* liftState)
{
    this->m_liftState = liftState;
    this->m_liftState->setContext(*this);
}
void    Context::open()
{
    this->m_liftState->open();
}
void    Context::close()
{
    this->m_liftState->close();
}
void    Context::run()
{
    this->m_liftState->run();
}
void    Context::stop()
{
    this->m_liftState->stop();
}

//抽象电梯状态 定义
void LiftState::setContext(Context &context)
{
    this->m_context = &context;
}

//关闭状态 定义
void    ClosingState::open()
{
    this->m_context->setLiftState(m_context->m_openningState);
    this->m_context->getLiftState()->open();
}
void    ClosingState::close()
{
    qDebug() << "close";
}
void    ClosingState::run()
{
    this->m_context->setLiftState(m_context->m_runningState);
    this->m_context->getLiftState()->run();
}
void    ClosingState::stop()
{
    this->m_context->setLiftState(m_context->m_stoppingState);
    this->m_context->getLiftState()->stop();
}


//敞门状态 定义
void    OpenningState::open()
{
    qDebug() << "open";
}
void    OpenningState::close()
{
    this->m_context->setLiftState(m_context->m_closingState);
    this->m_context->getLiftState()->close();
}
void    OpenningState::run(){}
void    OpenningState::stop(){}

//运行状态 定义
void    RunningState::open(){}
void    RunningState::close(){}

void    RunningState::run()
{
    qDebug() << "run";
}
void    RunningState::stop()
{
    this->m_context->setLiftState(m_context->m_stoppingState);
    this->m_context->getLiftState()->stop();
}

//停止状态 定义
void    StoppingState::open()
{
    this->m_context->setLiftState(m_context->m_openningState);
    this->m_context->getLiftState()->open();
}
void    StoppingState::close(){}
void    StoppingState::run()
{
    this->m_context->setLiftState(m_context->m_runningState);
    this->m_context->getLiftState()->run();
}
void    StoppingState::stop()
{
    qDebug() << "stop";
}


int main()
{
    Context context;   
    context.open();
    context.close();
    context.run();
    context.stop();
    
    return 0;
}

 


三、状态模式的应用

1. 优点:

  •  结构清晰。避免了过多的条件嵌套导致的程序的复杂性,提高可维护性。
  •  遵循设计原则。很好地体现了开闭原则和单一职责原则,每个状态都是一个子类,要增加状态就要增加子类,需要修改状态,只修改一个子类就好
  •  封装性好。状态变换放置到类的内部实现,外部的调用不用知道类内部如何实现状态和行为的变换。

2. 缺点:

子类会太多,也就是类膨胀。如果完全使用状态模式就会有太多的子类,不好管理,需要在项目中自己衡量。有很多方式可以解决这个状态问题,如在数据库中建立一个状态表,然后根据状态执行响应的操作。


3. 使用场景:

  •  行为随状态改变而改变的场景。例:权限设计,人员的状态不同即使执行相同的行为结果也会不同,在这种情况下需要考虑使用状态模式。
  •  条件、分支判断语句的替代者。在程序中大量使用switch或if潘丹语句会导致程序结构不清晰,逻辑混乱。

 

4. 注意事项:

 状态模式适用于当前某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的状态最好不要超过5个。

 


参考文献《秦小波. 设计模式之禅》(第2版) (华章原创精品) 机械工业出版社

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值