<<Head First设计模式>>之状态模式学习篇
2012-12-04 21:53
309 查看
最近在公司闲着没事干,看了一下<<HeadFirst设计模式>>一书,感觉还蛮有意思,设计模式涉及到OO的设计思想和OO的设计原则。这本书是采用Java语言描述的。由于我比较熟悉C++,所以看完之后想使用C++来实现。由于想要结合状态模式和工厂模式做Windows计算器,所以重点看了一下状态模式,并且将<<Head
First设计模式>>一书中以糖果机为例子讲述状态模式的例子使用C++做了一篇,加深我对状态模式的理解。大家如果看了之后觉得我写得有什么问题,欢迎大家提出自己的见解,大家交流学习一下,毕竟我也只是设计模式的初学者而已,开发经验不足。
下面是<<HeadFirst设计模式>>一书中糖果机的状态图及相应的Java代码和C++实现代码:
糖果机共有5个状态:没有25分钱、有25分钱、售出糖果、糖果售罄、赢家状态,这里从下面的UML状态图可以看到,Visio里使用椭圆形表示状态,还有引发糖果机状态发生转换的事件动作。
我使用Visio2003绘制的糖果机状态图,画得不太好,可能不是很标准,UML对于面向对象的软件设计很重要。
对应的Java代码如下:
运行结果截图如下:
对应的C++代码如下:
下面是程序运行结果截图:
记得以前在学校学Java得时候做的实验报告里面有一个关于地铁十字旋转门(turnstile)的状态模式练习,我感觉那个例子还比较好理解,因为来源于日常生活,例子描述如下:
在地铁十字旋转门(turnstile)的操作中,可以找到一个简单的有限状态机(FSM)。这个装置控制着乘客通往列车站台的大门。下面这个状态图展示了地铁十字转门的初步状态机。
但是这种实现方式至少有以下两个问题:
1)当状态数目不是很多的时候,Switch/Case可能可以搞定。但是当状态数目很多的时候(实际系统中也正是如此),维护一大组的Switch/Case语句将是一件异常困难并且容易出错的事情。
2)状态逻辑和动作实现没有分离。在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。这带来的后果就是系统的扩展性和维护得不到保证。
上面这幅图来源于<<HeadFirst设计模式>>的状态模式章节。
[/code]
下面是我的Java实现代码,不知道对不对。
下面是程序运行代码运行结果的贴图
另外我想使用MFC结合状态模式和工厂模式做一个标准版的Windows计算器,大概分成左操作数状态、操作符状态、右操作数状态、结果状态、错误异常状态这5个状态,然后可能还要区分单目运算符和双目运算符等等,等我做完这个练习后把关键的状态图和C++相关类设计代码也传上来,算是对状态模式学习的一个总结吧。
First设计模式>>一书中以糖果机为例子讲述状态模式的例子使用C++做了一篇,加深我对状态模式的理解。大家如果看了之后觉得我写得有什么问题,欢迎大家提出自己的见解,大家交流学习一下,毕竟我也只是设计模式的初学者而已,开发经验不足。
下面是<<HeadFirst设计模式>>一书中糖果机的状态图及相应的Java代码和C++实现代码:
糖果机共有5个状态:没有25分钱、有25分钱、售出糖果、糖果售罄、赢家状态,这里从下面的UML状态图可以看到,Visio里使用椭圆形表示状态,还有引发糖果机状态发生转换的事件动作。
我使用Visio2003绘制的糖果机状态图,画得不太好,可能不是很标准,UML对于面向对象的软件设计很重要。
对应的Java代码如下:
//State.java packageState; /* *状态接口State */ publicinterfaceState{ publicvoidinsertQuarter();//投入25分钱 publicvoidejectQuarter();//拒绝25分钱 publicvoidturnCrank();//转动曲柄 publicvoiddispense();//发放糖果 } //NoQuarterState.java packageState; importState.GumballMachine; /* *没有25分钱状态,实现了State接口 */ publicclassNoQuarterStateimplementsState{ GumballMachinegumballMachine; publicNoQuarterState(GumballMachinegumballMachine){ this.gumballMachine=gumballMachine; } //投入25分钱 publicvoidinsertQuarter(){ System.out.println("Youinsertaquarter"); gumballMachine.setState(gumballMachine.getHasQuarterState()); } //拒绝25分钱 publicvoidejectQuarter(){ System.out.println("Youhaven'tinsertaquarter"); } //转动曲柄 publicvoidturnCrank(){ System.out.println("Youturnedcrank,butyouthere'snoquarter"); } //发放糖果 publicvoiddispense(){ System.out.println("Youneedtopayfirst"); } } //HasQuarterState.java packageState; importjava.util.Random; importState.GumballMachine; /* *有25分钱状态,实现了State接口 */ publicclassHasQuarterStateimplementsState{ RandomrandomWinner=newRandom(System.currentTimeMillis());//首先我们增加一个随机数产生器,产生10%赢的机 会 GumballMachinegumballMachine; publicHasQuarterState(GumballMachinegumballMachine){ this.gumballMachine=gumballMachine; } //投入25分钱 publicvoidinsertQuarter(){ System.out.println("Youcannotinsertantherquarter"); } //拒绝25分钱 publicvoidejectQuarter(){ System.out.println("Quarterreturned"); gumballMachine.setState(gumballMachine.getNoQuarterState()); } //转动曲柄 publicvoidturnCrank(){ System.out.println("Youturned..."); intwinner=randomWinner.nextInt(10); System.out.println("winner="+winner); if((winner==0)&&(gumballMachine.getCount()>1)){ gumballMachine.setState(gumballMachine.getWinnerState()); }else{ gumballMachine.setState(gumballMachine.getSoldState()); } } //发放糖果 publicvoiddispense(){ System.out.println("Nogumballdispensed"); } } //SoldState.java packageState; importState.GumballMachine; /* *售出糖果状态,实现了State接口 */ publicclassSoldStateimplementsState{ GumballMachinegumballMachine; publicSoldState(GumballMachinegumballMachine){ this.gumballMachine=gumballMachine; } //投入25分钱 publicvoidinsertQuarter(){ System.out.println("Pleasewait,we'realreadygivingyouagumball"); } //拒绝25分钱 publicvoidejectQuarter(){ System.out.println("Sorry,youhavealreadyturncrank"); } //转动曲柄 publicvoidturnCrank(){ System.out.println("truntwice,doesn'tgiveyouanthorgamball!"); } //发放糖果 publicvoiddispense(){ gumballMachine.releaseBall(); if(gumballMachine.getCount()>0){ gumballMachine.setState(gumballMachine.getNoQuarterState()); }else{ System.out.println("Opps,outofgamball!"); gumballMachine.setState(gumballMachine.getSoldOutState()); } } } //SoldOutState.java packageState; importState.GumballMachine; /* *通过售罄状态,实现了State接口 */ publicclassSoldOutStateimplementsState{ GumballMachinegumballMachine; publicSoldOutState(GumballMachinegumballMachine){ this.gumballMachine=gumballMachine; } //投入25分钱 publicvoidinsertQuarter(){ System.out.println("Youcan'tinsertaquarter,themachineissoldout"); } //拒绝25分钱 publicvoidejectQuarter(){ //TODOAuto-generatedmethodstub System.out.println("Youcan'teject,youhaven'tinsertedaquarteryet"); } //转动曲柄 publicvoidturnCrank(){ //TODOAuto-generatedmethodstub System.out.println("Youturned,buttherearenogumballs"); } //发放糖果 publicvoiddispense(){ //TODOAuto-generatedmethodstub System.out.println("Nogumballdispensed"); } } //WinnerState.java packageState; importState.GumballMachine; /* *赢家状态,实现了State接口 */ publicclassWinnerStateimplementsState{ GumballMachinegumballMachine; publicWinnerState(GumballMachinegumballMachine){ this.gumballMachine=gumballMachine; } //投入25分钱 @Override publicvoidinsertQuarter(){ //TODOAuto-generatedmethodstub System.out.println("Pleasewait,we'realreadygivingyouagumball"); } //拒绝25分钱 @Override publicvoidejectQuarter(){ //TODOAuto-generatedmethodstub System.out.println("Sorry,youhavealreadyturncrank"); } //转动曲柄 @Override publicvoidturnCrank(){ //TODOAuto-generatedmethodstub System.out.println("truntwice,doesn'tgiveyouanthorgamball!"); } //发放糖果 @Override publicvoiddispense(){ //TODOAuto-generatedmethodstub System.out.println("You'reaWinner!Yougettwogumballsforyourquarter"); gumballMachine.releaseBall(); if(gumballMachine.getCount()==0){ gumballMachine.setState(gumballMachine.getSoldOutState()); }else{ gumballMachine.releaseBall(); if(gumballMachine.getCount()>0){ gumballMachine.setState(gumballMachine.getNoQuarterState()); }else{ System.out.println("Opps,outofgamball!"); gumballMachine.setState(gumballMachine.getSoldOutState()); } } } } //糖果机上下文环境类Java源文件GumballMachine.java packageState; importState.HasQuarterState; importState.NoQuarterState; importState.SoldOutState; importState.SoldState; importState.WinnerState; importState.State; /* *糖果机器上下文环境接口类GumballMachine */ publicclassGumballMachine{ //状态实例 StatesoldOutState; StatenoQuarterState; StatehasQuarterState; StatesoldState; StatewinnerState; //实例变量state,初始化为糖果售罄状态 Statestate=soldOutState; //记录机器内装有糖果的数目,开始机器是没有装糖果的 intcount=0; //构造器取得糖果的初始数目并把它放在一个实例变量count中 publicGumballMachine(intnumberGumballs){ //每种状态都创建一个状态实例 soldOutState=newSoldOutState(this); noQuarterState=newNoQuarterState(this); hasQuarterState=newHasQuarterState(this); soldState=newSoldState(this); winnerState=newWinnerState(this); this.count=numberGumballs; //若超过0颗糖果,就将状态设置为NoQuarterState if(numberGumballs>0){ state=noQuarterState; } } //取得机器内的糖果数目 publicintgetCount(){ returncount; } //取得糖果售罄状态 publicStategetSoldOutState(){ returnsoldOutState; } //取得没有25分钱状态 publicStategetNoQuarterState(){ returnnoQuarterState; } //取得拥有25分钱 publicStategetHasQuarterState(){ returnhasQuarterState; } //取得售出糖果状态 publicStategetSoldState(){ returnsoldState; } //取得赢家状态 publicStategetWinnerState(){ returnwinnerState; } //投入25分钱 publicvoidinsertQuarter(){ state.insertQuarter(); } //拒绝25分钱 publicvoidejectQuarter(){ state.ejectQuarter(); } //转动曲柄 publicvoidturnCrank(){ state.turnCrank(); state.dispense(); } //设置状态 publicvoidsetState(Statestate){ this.state=state; } //糖果滚出来一个 publicvoidreleaseBall(){ System.out.println("Agumballcomesrollingoutofthesolt..."); if(count!=0){ count--; } } } //测试糖果机的Java源文件GumballMachineTestDrive.java packageState; /* *糖果机测试驱动程序:GumballMachineTestDrive.java */ publicclassGumballMachineTestDrive{ /** *@paramargs */ publicstaticvoidmain(String[]args){ GumballMachinegumballMachine=newGumballMachine(5); System.out.println(gumballMachine); System.out.println("Thecurrentgumballnumberis:"+gumballMachine.getCount()); System.out.println("****************************************"); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); System.out.println(gumballMachine); System.out.println("Thecurrentgumballnumberis:"+gumballMachine.getCount()); System.out.println("****************************************"); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); System.out.println(gumballMachine); System.out.println("Thecurrentgumballnumberis:"+gumballMachine.getCount()); System.out.println("****************************************"); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); System.out.println(gumballMachine); System.out.println("Thecurrentgumballnumberis:"+gumballMachine.getCount()); System.out.println("****************************************"); } }
运行结果截图如下:
对应的C++代码如下:
//State抽象基类 //State.h #pragmaonce classState { public: State(void); public: ~State(void); public: //投入25分钱 virtualvoidinsertQuarter(void)=0; public: //退回25分钱 virtualvoidejectQuarter(void)=0; public: //转动曲柄 virtualvoidturnCrank(void)=0; public: //发放糖果 virtualvoiddispense(void)=0; }; //State.cpp #include"State.h" State::State(void) { } State::~State(void) { } //没有25分钱状态类NoQuarterState //NoQuarterState.h #pragmaonce #include"state.h" #include"GumballMachine.h" classNoQuarterState: publicState { public: NoQuarterState(GumballMachine*pGumballMachine); public: ~NoQuarterState(void); public: //投入25分钱 voidinsertQuarter(void); public: //退回25分钱 voidejectQuarter(void); public: //转动曲柄 voidturnCrank(void); public: //发放糖果 voiddispense(void); private: //糖果机实例变量 GumballMachine*m_pGumballMachine; }; //NoQuarterState.cpp #include"NoQuarterState.h" #include<iostream> usingnamespacestd; NoQuarterState::NoQuarterState(GumballMachine*pGumballMachine) { this->m_pGumballMachine=pGumballMachine; } NoQuarterState::~NoQuarterState(void) { } //投入25分钱 voidNoQuarterState::insertQuarter(void) { cout<<"Youinsertedaquarter"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getHasQuarterState()); } //退回25分钱 voidNoQuarterState::ejectQuarter(void) { cout<<"Youhaven'tinsertedaquarter"<<endl; } //转动曲柄 voidNoQuarterState::turnCrank(void) { cout<<"Youturned,butthere'snoquarter"<<endl; } //发放糖果 voidNoQuarterState::dispense(void) { cout<<"Youneedtopayfirst"<<endl; } //有25分钱状态HasQuarterState //HasQuarterState.h #pragmaonce #include"state.h" #include"GumballMachine.h" classHasQuarterState: publicState { public: HasQuarterState(GumballMachine*pGumballMachine); public: ~HasQuarterState(void); public: //投入25分钱 voidinsertQuarter(void); public: //退回25分钱 voidejectQuarter(void); public: //转动曲柄 voidturnCrank(void); public: //发放糖果 voiddispense(void); private: //糖果机实例变量 GumballMachine*m_pGumballMachine; }; //HasQuarterState.cpp #include"HasQuarterState.h" #include<iostream> #include<cstdlib> #include<ctime> usingnamespacestd; HasQuarterState::HasQuarterState(GumballMachine*pGumballMachine) { this->m_pGumballMachine=pGumballMachine; } HasQuarterState::~HasQuarterState(void) { } //投入25分钱 voidHasQuarterState::insertQuarter(void) { cout<<"Youcan'tinsertanotherquarter"<<endl; } //退回25分钱 voidHasQuarterState::ejectQuarter(void) { cout<<"Quarterreturned"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getNoQuarterState()); } //转动曲柄 voidHasQuarterState::turnCrank(void) { cout<<"Youturned..."<<endl; //srand(time(0));//用时间作种子,使每次随即的数字不一样 //intwinner=(int)(10.0*rand()/(RAND_MAX+1.0));//产生随机数 intwinner=rand()%10;//产生随机数 cout<<winner<<endl; if((winner==3)&&(m_pGumballMachine->getCount()>1)) { m_pGumballMachine->setState(m_pGumballMachine->getWinnerState()); }else{ m_pGumballMachine->setState(m_pGumballMachine->getSoldState()); } } //发放糖果 voidHasQuarterState::dispense(void) { cout<<"Nogumballdispensed"<<endl; } //售出糖果状态SoldState //SoldState.h #pragmaonce #include"state.h" #include"GumballMachine.h" classSoldState: publicState { public: SoldState(GumballMachine*pGumballMachine); public: ~SoldState(void); public: //投入25分钱 voidinsertQuarter(void); //退回25分钱 voidejectQuarter(void); //转动曲柄 voidturnCrank(void); //发放糖果 voiddispense(void); private: //糖果机实例变量 GumballMachine*m_pGumballMachine; }; //SoldState.cpp #include"SoldState.h" #include<iostream> usingnamespacestd; SoldState::SoldState(GumballMachine*pGumballMachine) { this->m_pGumballMachine=pGumballMachine; } SoldState::~SoldState(void) { } //投入25分钱 voidSoldState::insertQuarter(void) { cout<<"Pleasewait,we'realreadygivingyouagumball"<<endl; } //退回25分钱 voidSoldState::ejectQuarter(void) { cout<<"Sorry,youalreadyturnedtheCrank"<<endl; } //转动曲柄 voidSoldState::turnCrank(void) { cout<<"Turningtwicedoesn'tgetyouanothergumball!"<<endl; } //发放糖果 voidSoldState::dispense(void) { m_pGumballMachine->releaseBall(); if(m_pGumballMachine->getCount()>0) { m_pGumballMachine->setState(m_pGumballMachine->getNoQuarterState()); } else { cout<<"Oops,outofgumballs!"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getSoldOutState()); } } //糖果售罄状态SoldOutState类 //SoldOutState.h #pragmaonce #include"state.h" #include"GumballMachine.h" classSoldOutState: publicState { public: SoldOutState(GumballMachine*pGumballMachine); public: ~SoldOutState(void); public: //投入25分钱 voidinsertQuarter(void); //退回25分钱 voidejectQuarter(void); //转动曲柄 voidturnCrank(void); //发放糖果 voiddispense(void); private: //糖果机实例变量 GumballMachine*m_pGumballMachine; }; //SoldOutState.cpp #include"SoldOutState.h" #include<iostream> usingnamespacestd; SoldOutState::SoldOutState(GumballMachine*pGumballMachine) { this->m_pGumballMachine=pGumballMachine; } SoldOutState::~SoldOutState(void) { } //投入25分钱 voidSoldOutState::insertQuarter(void) { cout<<"Youcan'tinsertaquarter,themachineissoldout"<<endl; } //退回25分钱 voidSoldOutState::ejectQuarter(void) { cout<<"Youcan'teject,youhaven'tinsertedaquarteryet"<<endl; } //转动曲柄 voidSoldOutState::turnCrank(void) { cout<<"Youturned,buttherearenogumballs"<<endl; } //发放糖果 voidSoldOutState::dispense(void) { cout<<"Nogumballdispensed"<<endl; } //赢家状态WinnerState类 //WinnerState.h #pragmaonce #include"state.h" #include"GumballMachine.h" classWinnerState: publicState { public: WinnerState(GumballMachine*pGumballMachine); public: ~WinnerState(void); public: //投入25分钱 voidinsertQuarter(void); public: //退回25分钱 voidejectQuarter(void); public: //转动曲柄 voidturnCrank(void); public: //发放糖果 voiddispense(void); private: //糖果机实例变量 GumballMachine*m_pGumballMachine; }; //WinnerState.cpp #include"WinnerState.h" #include<iostream> usingnamespacestd; WinnerState::WinnerState(GumballMachine*pGumballMachine) { this->m_pGumballMachine=pGumballMachine; } WinnerState::~WinnerState(void) { } //投入25分钱 voidWinnerState::insertQuarter(void) { cout<<"Pleasewait,we'realreadygivingyouagumball"<<endl; } //退回25分钱 voidWinnerState::ejectQuarter(void) { cout<<"Sorry,youalreadyturnedtheCrank"<<endl; } //转动曲柄 voidWinnerState::turnCrank(void) { cout<<"Turningtwicedoesn'tgetyouanothergumball!"<<endl; } //发放糖果 voidWinnerState::dispense(void) { cout<<"You'reaWinner!Yougettwogumballsforyourquarter"; m_pGumballMachine->releaseBall(); if(m_pGumballMachine->getCount()==0) { m_pGumballMachine->setState(m_pGumballMachine->getSoldOutState()); } else{ m_pGumballMachine->releaseBall(); if(m_pGumballMachine->getCount()>0){ m_pGumballMachine->setState(m_pGumballMachine->getNoQuarterState()); }else{ cout<<"Oops,outofgumballs!"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getSoldOutState()); } } } //糖果机上下文环境GumballMachine类 //GumballMachine.h #pragmaonce #include"State.h" classGumballMachine { public: GumballMachine(intnumberGumballs=0); public: ~GumballMachine(void); private: //状态类的指针 State*m_pState; private: //记录机器内的糖果数目 intm_count; State*m_pSoldOutState; State*m_pNoQuarterState; State*m_pHasQuarterState; State*m_pSoldState; State*m_pWinnerState; public: voidinsertQuarter(void); public: //退回25分钱 voidejectQuarter(void); public: //转动曲柄 voidturnCrank(void); public: //设置状态 voidsetState(State*pState); public: //释放糖果 voidreleaseBall(void); public: //获取当前糖果的数目 intgetCount(void); //获取发放糖果状态 State*getSoldState(void); //获取拥有25分钱状态 State*getHasQuarterState(void); //获取没有25分钱状态 State*getNoQuarterState(void); //获取糖果售罄状态 State*getSoldOutState(void); public: //获取赢家状态 State*getWinnerState(void); }; //GumballMachine.cpp #include"GumballMachine.h" #include"NoQuarterState.h" #include"HasQuarterState.h" #include"SoldOutState.h" #include"SoldState.h" #include"WinnerState.h" #include<iostream> usingnamespacestd; GumballMachine::GumballMachine(intnumberGumballs) { m_pSoldOutState=newSoldOutState(this); m_pNoQuarterState=newNoQuarterState(this); m_pHasQuarterState=newHasQuarterState(this); m_pSoldState=newSoldState(this); this->m_count=numberGumballs; m_pState=m_pSoldOutState; if(numberGumballs>0) { m_pState=m_pNoQuarterState; } } GumballMachine::~GumballMachine(void) { deletem_pSoldOutState; deletem_pNoQuarterState; deletem_pHasQuarterState; deletem_pSoldState; } voidGumballMachine::insertQuarter(void) { m_pState->insertQuarter(); } //退回25分钱 voidGumballMachine::ejectQuarter(void) { m_pState->ejectQuarter(); } //转动曲柄 voidGumballMachine::turnCrank(void) { m_pState->turnCrank(); m_pState->dispense(); } //设置状态 voidGumballMachine::setState(State*pState) { this->m_pState=pState; } //释放糖果 voidGumballMachine::releaseBall(void) { cout<<"Agumballcomesrollingoutofthesolt..."; if(m_count!=0) { m_count=m_count-1; } } //获取当前糖果的数目 intGumballMachine::getCount(void) { returnm_count; } //获取发放糖果状态 State*GumballMachine::getSoldState(void) { returnm_pSoldState; } //获取拥有25分钱状态 State*GumballMachine::getHasQuarterState(void) { returnm_pHasQuarterState; } //获取没有25分钱状态 State*GumballMachine::getNoQuarterState(void) { returnm_pNoQuarterState; } //获取糖果售罄状态 State*GumballMachine::getSoldOutState(void) { returnm_pSoldOutState; } //获取赢家状态 State*GumballMachine::getWinnerState(void) { returnm_pWinnerState; } //测试主函数文件TestDriver.cpp #include"GumballMachine.h" #include<iostream> usingnamespacestd; intmain() { srand(time(NULL));//以系统时间作为种子,设置随机数种子
GumballMachine*pGumballMachine=newGumballMachine(5); pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"thegumballcountis:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"thegumballcountis:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"thegumballcountis:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"thegumballcountis:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"thegumballcountis:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"thegumballcountis:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"thegumballcountis:"<<pGumballMachine->getCount()<<endl; return0; }
下面是程序运行结果截图:
记得以前在学校学Java得时候做的实验报告里面有一个关于地铁十字旋转门(turnstile)的状态模式练习,我感觉那个例子还比较好理解,因为来源于日常生活,例子描述如下:
在地铁十字旋转门(turnstile)的操作中,可以找到一个简单的有限状态机(FSM)。这个装置控制着乘客通往列车站台的大门。下面这个状态图展示了地铁十字转门的初步状态机。
状态图由四个部分组成。图中的矩形框表示一个状态(state),箭头表示状态的迁移,箭头上面有两个元素:前面那个是事件(event),后面那个是响应动作(action)。
(1)若状态机在Locked(锁)状态,收到一个coin(投币)事件,则执行unlock(开门)操作,并迁移到Unlocked(开)状态。
(2)若状态机在Locked(锁)状态,收到一个pass(人员通过)事件,则执行alarm(警报)操作,没有状态迁移。
(3)若状态机在Unlocked(开)状态,收到一个pass(人员通过)事件,则执行lock操作,并迁移到Locked(锁)状态。
(4)若状态机在Unlocked(开)状态,收到一个coin(投币)事件,则执行refund(退款)操作,没有状态迁移。
我们用一般的方法描述这件事应该是这样:
/* *用TurnstileController封装旋转门能做的所有操作 */ classTurnstileController{ publicvoidunlock(){ System.out.println("正在执行开门操作…"); } publicvoidalarm(){ System.out.println("注意!有人强行越过旋转门…"); } publicvoidlock(){ System.out.println("正在执行关门操作…"); } publicvoidrefund(){ System.out.println("退款中…"); } } /* *Turnstile:旋转门类 */ classTurnstile{ //用来代表状态的两个常量 publicstaticfinalintLOCKED=0; publicstaticfinalintUNLOCKED=1; //用来代表事件的常量 publicstaticfinalintCOIN=0; publicstaticfinalintPASS=1; //当前旋转门的状态 publicintstate=LOCKED; publicTurnstileControllertController; publicTurnstile(TurnstileControllertController){ this.tController=tController; } //当新的事件发生时调用此方法,同时把事件代码传递给它 publicvoideventHappen(intevent){ switch(state){ caseLOCKED: switch(event){ caseCOIN: tController.unlock(); state=UNLOCKED; break; casePASS: tController.alarm(); break; } break; caseUNLOCKED: switch(event){ caseCOIN: tController.refund(); break; casePASS: tController.lock(); state=LOCKED; break; } break; } } } publicclassTurnstileTest{ publicstaticvoidmain(String[]args){ Turnstileturnstile=newTurnstile(newTurnstileController()); turnstile.eventHappen(Turnstile.COIN); turnstile.eventHappen(Turnstile.PASS); turnstile.eventHappen(Turnstile.PASS); turnstile.eventHappen(Turnstile.COIN); turnstile.eventHappen(Turnstile.COIN); } }
但是这种实现方式至少有以下两个问题:
1)当状态数目不是很多的时候,Switch/Case可能可以搞定。但是当状态数目很多的时候(实际系统中也正是如此),维护一大组的Switch/Case语句将是一件异常困难并且容易出错的事情。
2)状态逻辑和动作实现没有分离。在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。这带来的后果就是系统的扩展性和维护得不到保证。
下面介绍State模式:在State模式中我们将状态逻辑和动作实现进行分离。当一个操作中要维护大量的case分支语句,并且这些分支依赖于对象的状态。State模式将每一个分支都封装到独立的类中。State模式典型的类图为:
State接口定义了所有状态的共同接口(能够发生的所有事件),任何状态都实现这个接口,这样一来,状态之间可以相互替换 |
Context(上下文)拥有一个当前的内部状态 |
不管什么时候发生一个事件(someEventHappen),Context将委托给具体的状态类去处理 |
具体状态,处理Context的请求,每一个具体状态实现了在该状态下,针对某一事件的特定响应动作和下一步的状态迁移 |
上面这幅图来源于<<HeadFirst设计模式>>的状态模式章节。
代码如下:
[code]interfaceState{
publicvoidsomeEventHappen(Contextc);
}
classStateAimplementsState{
publicvoidsomeEventHappen(Contextc){
c.actionA();
c.state=newStateB();
}
}
classStateBimplementsState{
publicvoidsomeEventHappen(Contextc){
c.actionB();
c.state=newStateA();
}
}
classContext{
publicStatestate=newStateA();
publicvoidsomeEventHappen(){
state.someEventHappen(this);
}
publicvoidactionA(){
System.out.println("actionAisgoingon...");
}
publicvoidactionB(){
System.out.println("acitonBisgoingon...");
}
}
publicclassStateTest{
publicstaticvoidmain(String[]args){
Contextc=newContext();
c.someEventHappen();
c.someEventHappen();
}
}
[/code]
注意该代码实现了如下的状态机:
你的任务:
参考以上描述的状态模式,利用状态模式重新设计并编写“地铁十字旋转门(turnstile)”问题。
下面是我的Java实现代码,不知道对不对。
//MyTurstileTest.java
interfaceState{
publicabstractvoidDropCoinEventHappen(Contextc);
publicabstractvoidPassEventHappen(Contextc);
}
classContext{
privateStatestate=newLockedState();
publicvoidCoinEventHappen(){
state.DropCoinEventHappen(this);
}
publicvoidPassEventHappen(){
state.PassEventHappen(this);
}
publicvoidunlock(){
System.out.println("正在执行开门操作.......");
state=newUnLockedState();
}
publicvoidalarm(){
System.out.println("注意!有人强行越过旋转门.......");
state=newLockedState();
}
publicvoidlock(){
System.out.println("正在执行关门操作........");
state=newLockedState();
}
publicvoidrefund(){
System.out.println("退款中........");
state=newUnLockedState();
}
}
classLockedStateimplementsState{
publicvoidDropCoinEventHappen(Contextc){
c.unlock();//执行开门操作
}
publicvoidPassEventHappen(Contextc){
c.alarm();//报警
}
}
classUnLockedStateimplementsState{
publicvoidDropCoinEventHappen(Contextc){
c.refund();//退款
}
publicvoidPassEventHappen(Contextc){
c.lock();//执行关门操作
}
}
publicclassMyTurstileTest{
publicstaticvoidmain(String[]args){
Contextc=newContext();
System.out.println("地铁十字旋转门初始态为关的状态......");
//起始状态地铁十字旋转门(turnstile)默认处于关的状态
c.CoinEventHappen();
//turnstile状态为关时,发生投币操作,事件发生后turnstile状态为开
c.PassEventHappen();
//turnstile状态为开时,发生人员通过事件,事件发生后turnstile状态为关
c.PassEventHappen();
//turnstile状态为关时,发生人员通过事件,事件发生后turnstile状态为开
c.CoinEventHappen();
//turstile状态为关时,发生投币操作,事件发生后turnstile状态为开
}
}
下面是程序运行代码运行结果的贴图
另外我想使用MFC结合状态模式和工厂模式做一个标准版的Windows计算器,大概分成左操作数状态、操作符状态、右操作数状态、结果状态、错误异常状态这5个状态,然后可能还要区分单目运算符和双目运算符等等,等我做完这个练习后把关键的状态图和C++相关类设计代码也传上来,算是对状态模式学习的一个总结吧。
相关文章推荐
- <十二>读<<大话设计模式>>之状态模式
- <自已动手写操作系统>学习扎记之保护模式
- <十二>读<<大话设计模式>>之状态模式
- <C/C++ 版> 设计模式 学习之 策略模式
- <C/C++ 版> 设计模式 学习之 工厂模式 <2>
- <C/C++ 版> 设计模式 学习之 策略模式+工厂模式
- <C/C++ 版> 设计模式 学习之 工厂模式 <1>
- <学习正则表达式>(1)
- <转载>常见的23种设计模式
- <一>Strom实时计算学习笔记
- <<Practical Common Lisp>> 学习笔记一
- <特效练习>学习中制作
- <Java Web学习初级阶段>表格实现简单的注册页面
- <<Python基础教程>>学习笔记 | 第04章 | 字典
- <a>链接的不同状态
- <<Python基础教程>>学习笔记 | 第11章 | 文件和素材
- 【2015/11/15】 数据结构学习日志_Day16 链表 我的<LinkList.c>
- <Python基础教程>第三章_学习心得
- <<unix/linux programming>>学习标记整理
- <学习正则表达式>(2)