状态模式
如何去描述状态机?
假设你需要实例化一台电梯,并模仿出电梯的四个状态:开启、关闭、运行、停止。也许你会这么写
cpp
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分支来判断当前动作是否有效,以及更新当前状态。于是有了下面的代码
cpp
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内部实现。具体代码如下:
cpp
#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();
}
状态模式的优势:
当由新的状态加入时,只需要扩展子类,而不需要过多地更改原有代码。遵守了开闭原则。
当动作和状态更新等逻辑交由状态类内部实现,实现了单一性设计原则。
参考
Java设计模式------状态模式(STATE PATTERN)_java中state pattern-CSDN博客