参考:Java设计模式——状态模式(STATE PATTERN)_java中state pattern-CSDN博客
状态模式
如何去描述状态机?
假设你需要实例化一台电梯,并模仿出电梯的四个状态:开启、关闭、运行、停止。也许你会这么写
class ILift{ public: virtual void open(){} virtual void close(){} virtual void run(){} virtual void stop(){} }; class Lift : public ILift{ public: void open(){ std::cout << "电梯门关闭..." << std::endl; } void close(){ std::cout << "电梯门开启..." << std::endl; } void run(){ std::cout << "电梯上下跑起来..." << std::endl; } void stop(){ std::cout << "电梯停止了..." << std::endl; } }; int main(){ ILift* lift = new Lift(); lift->open(); lift->close(); lift->run(); lift->stop(); }
这样写未免太草率了。因为电梯在门开启的时候一般是不能运行的,在运行的时候一般也不会门开启,而在停止工作状态一般不会再去执行关门这个动作。所以需要设置一些状态去限制这台电梯的行为。于是在类Lift中存储电梯目前的状态,在执行每个动作的时候用swith分支来判断当前动作是否有效,以及更新当前状态。于是有了下面的代码
class ILift{ public: virtual void setState(int state){}; virtual void open(){} virtual void close(){} virtual void run(){} virtual void stop(){} }; class Lift : public ILift{ public: Lift(int state):state(state){} void setState(int state){ this->state = state; } void close(){ switch(state){ case OPENING_STATE: closeWithoutLogic(); setState(CLOSING_STATE); break; case CLOSING_STATE: break; case RUNNING_STATE: break; case STOPPING_STATE: break; } } void open(){ switch(state){ case OPENING_STATE: break; case CLOSING_STATE: openWithoutLogic(); setState(OPENING_STATE); break; case RUNNING_STATE: break; case STOPPING_STATE: openWithoutLogic(); setState(OPENING_STATE); } } void run(){ switch(state){ case OPENING_STATE: break; case CLOSING_STATE: runWithoutLogic(); setState(RUNNING_STATE); break; case RUNNING_STATE: break; case STOPPING_STATE: runWithoutLogic(); setState(RUNNING_STATE); } } void stop(){ switch(state){ case OPENING_STATE: break; case CLOSING_STATE: stopWithoutLogic(); setState(STOPPING_STATE); break; case RUNNING_STATE: stopWithoutLogic(); setState(STOPPING_STATE); break; case STOPPING_STATE: break; } } void closeWithoutLogic(){ std::cout << "电梯门关闭..." << std::endl; } void openWithoutLogic() { std::cout << "电梯门开启..." << std::endl; } void runWithoutLogic() { std::cout << "电梯上下跑起来..." << std::endl; } void stopWithoutLogic() { std::cout << "电梯停止了..." << std::endl; } private: int state; }; int main(){ ILift* lift = new Lift(STATE(OPENING_STATE)); lift->close(); // 关闭 lift->open(); // 开启 lift->run(); // 无动作 lift->stop(); // 无动作 lift->close(); // 关闭 }
这个类的实现代码特别长,内部包含了太多的switch语句。而且当需要增加状态时,比如说电梯停电状态和电梯维修状态,就需要去更改里面的switch语句。这样写违背了开闭原则以及单一性原则。为了在增加状态的时候尽量少的修改原有代码,可以将swtich中的每个状态抽离出来单独包装成类。
创建context类,在context类中存有LiftState对象用来记录当前的状态。此时context目前拥有四种状态对象,用指针维护。每种状态的逻辑由各自类在内部实现。当电梯发生动作,即context调用函数时,函数内部会调用当前state对应的方法,于是这部分逻辑转交由state内部实现。具体代码如下:
#include<iostream> #include<string> using namespace std; class ContextBase; class LiftState{ public: void setContext(ContextBase* context){ this->mContext = context; } virtual void open(){} virtual void close(){} virtual void run(){} virtual void stop(){} ContextBase* getContext(){ return mContext; } public: ContextBase* mContext; }; class ContextBase{ public: ContextBase(){} virtual LiftState* getLiftState(){} virtual LiftState* getOpenningState(){} virtual LiftState* getClosingState(){} virtual LiftState* getRunningState(){} virtual LiftState* getStoppingState(){} virtual void setLiftState(LiftState* liftState){} virtual void open(){} virtual void close(){} virtual void run(){} virtual void stop(){} public: LiftState* liftState; }; class OpenningState : public LiftState{ void open(){ std::cout << "lift open..." << std::endl; } void close(){ mContext->setLiftState(mContext->getClosingState()); mContext->getLiftState()->close(); } void run(){} void stop(){} }; class ClosingState : public LiftState{ void open(){ mContext->setLiftState(mContext->getOpenningState()); mContext->getLiftState()->open(); } void close(){ std::cout << "lift close..." << std::endl; } void run(){ mContext->setLiftState(mContext->getRunningState()); mContext->getLiftState()->run(); } void stop(){ mContext->setLiftState(mContext->getStoppingState()); mContext->getLiftState()->stop(); } }; class RunningState : public LiftState{ void open(){ } void close(){ } void run(){ std::cout << "lift running..." << std::endl; } void stop(){ mContext->setLiftState(mContext->getStoppingState()); mContext->getLiftState()->stop(); } }; class StoppingState : public LiftState{ void open(){ mContext->setLiftState(mContext->getOpenningState()); mContext->getLiftState()->open(); } void close(){ } void run(){ mContext->setLiftState(mContext->getRunningState()); mContext->getLiftState()->run(); } void stop(){ std::cout << "lift stopping..." << std::endl; } }; class Context : public ContextBase{ public: Context(){} LiftState* getLiftState(){ return liftState; } LiftState* getOpenningState(){ return openningState; } LiftState* getClosingState(){ return closingState; } LiftState* getRunningState(){ return runningState; } LiftState* getStoppingState(){ return stoppingState; } void setLiftState(LiftState* liftState){ this->liftState = liftState; this->liftState->setContext(this); } void open(){ liftState->open(); } void close(){ liftState->close(); } void run(){ liftState->run(); } void stop(){ liftState->stop(); } public: LiftState* openningState = new OpenningState(); LiftState* closingState = new ClosingState(); LiftState* runningState = new RunningState(); LiftState* stoppingState = new StoppingState(); }; int main(){ Context* context = new Context; context->setLiftState(new ClosingState()); context->open(); context->close(); context->run(); context->stop(); }
状态模式的优势:
当由新的状态加入时,只需要扩展子类,而不需要过多地更改原有代码。遵守了开闭原则。
当动作和状态更新等逻辑交由状态类内部实现,实现了单一性设计原则。