狀態(tài)模式
如何去描述狀態(tài)機(jī)?
假設(shè)你需要實(shí)例化一臺(tái)電梯,并模仿出電梯的四個(gè)狀態(tài):開(kāi)啟、關(guān)閉、運(yùn)行、停止。也許你會(huì)這么寫(xiě)
class ILift{
public:
virtual void open(){}
virtual void close(){}
virtual void run(){}
virtual void stop(){}
};
class Lift : public ILift{
public:
void open(){ std::cout << "電梯門(mén)關(guān)閉..." << std::endl; }
void close(){ std::cout << "電梯門(mén)開(kāi)啟..." << std::endl; }
void run(){ std::cout << "電梯上下跑起來(lái)..." << std::endl; }
void stop(){ std::cout << "電梯停止了..." << std::endl; }
};
int main(){
ILift* lift = new Lift();
lift->open();
lift->close();
lift->run();
lift->stop();
}
這樣寫(xiě)未免太草率了。因?yàn)殡娞菰陂T(mén)開(kāi)啟的時(shí)候一般是不能運(yùn)行的,在運(yùn)行的時(shí)候一般也不會(huì)門(mén)開(kāi)啟,而在停止工作狀態(tài)一般不會(huì)再去執(zhí)行關(guān)門(mén)這個(gè)動(dòng)作。所以需要設(shè)置一些狀態(tài)去限制這臺(tái)電梯的行為。于是在類(lèi)Lift中存儲(chǔ)電梯目前的狀態(tài),在執(zhí)行每個(gè)動(dòng)作的時(shí)候用swith分支來(lái)判斷當(dāng)前動(dòng)作是否有效,以及更新當(dāng)前狀態(tài)。于是有了下面的代碼
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 << "電梯門(mén)關(guān)閉..." << std::endl; }
void openWithoutLogic() { std::cout << "電梯門(mén)開(kāi)啟..." << std::endl; }
void runWithoutLogic() { std::cout << "電梯上下跑起來(lái)..." << std::endl; }
void stopWithoutLogic() { std::cout << "電梯停止了..." << std::endl; }
private:
int state;
};
int main(){
ILift* lift = new Lift(STATE(OPENING_STATE));
lift->close(); // 關(guān)閉
lift->open(); // 開(kāi)啟
lift->run(); // 無(wú)動(dòng)作
lift->stop(); // 無(wú)動(dòng)作
lift->close(); // 關(guān)閉
}
這個(gè)類(lèi)的實(shí)現(xiàn)代碼特別長(zhǎng),內(nèi)部包含了太多的switch語(yǔ)句。而且當(dāng)需要增加狀態(tài)時(shí),比如說(shuō)電梯停電狀態(tài)和電梯維修狀態(tài),就需要去更改里面的switch語(yǔ)句。這樣寫(xiě)違背了開(kāi)閉原則以及單一性原則。為了在增加狀態(tài)的時(shí)候盡量少的修改原有代碼,可以將swtich中的每個(gè)狀態(tài)抽離出來(lái)單獨(dú)包裝成類(lèi)。
創(chuàng)建context類(lèi),在context類(lèi)中存有LiftState對(duì)象用來(lái)記錄當(dāng)前的狀態(tài)。此時(shí)context目前擁有四種狀態(tài)對(duì)象,用指針維護(hù)。每種狀態(tài)的邏輯由各自類(lèi)在內(nèi)部實(shí)現(xiàn)。當(dāng)電梯發(fā)生動(dòng)作,即context調(diào)用函數(shù)時(shí),函數(shù)內(nèi)部會(huì)調(diào)用當(dāng)前state對(duì)應(yīng)的方法,于是這部分邏輯轉(zhuǎn)交由state內(nèi)部實(shí)現(xiàn)。具體代碼如下:
#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();
}
狀態(tài)模式的優(yōu)勢(shì):
當(dāng)由新的狀態(tài)加入時(shí),只需要擴(kuò)展子類(lèi),而不需要過(guò)多地更改原有代碼。遵守了開(kāi)閉原則。
當(dāng)動(dòng)作和狀態(tài)更新等邏輯交由狀態(tài)類(lèi)內(nèi)部實(shí)現(xiàn),實(shí)現(xiàn)了單一性設(shè)計(jì)原則。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-817443.html
參考
Java設(shè)計(jì)模式——狀態(tài)模式(STATE PATTERN)_java中state pattern-CSDN博客???????文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-817443.html
到了這里,關(guān)于(十一)Head first design patterns狀態(tài)模式(c++)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!