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

xiaoxiao2021-07-06  390

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


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

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版) (华章原创精品) 机械工业出版社

转载请注明原文地址: https://www.6miu.com/read-4821493.html

最新回复(0)