最近在公司闲着没事干,看了一下<<Head First设计模式>>一书,感觉还蛮有意思,设计模式涉及到OO的设计思想和OO的设计原则。这本书是采用Java语言描述的。由于我比较熟悉C++,所以看完之后想使用C++来实现。由于想要结合状态模式和工厂模式做Windows计算器,所以重点看了一下状态模式,并且将<<Head First设计模式>>一书中以糖果机为例子讲述状态模式的例子使用C++做了一篇,加深我对状态模式的理解。大家如果看了之后觉得我写得有什么问题,欢迎大家提出自己的见解,大家交流学习一下,毕竟我也只是设计模式的初学者而已,开发经验不足。
下面是<<Head First设计模式>>一书中糖果机的状态图及相应的Java代码和C++实现代码:
糖果机共有5个状态:没有25分钱、有25分钱、售出糖果、糖果售罄、赢家状态,这里从下面的UML状态图可以看到,Visio里使用椭圆形表示状态,还有引发糖果机状态发生转换的事件动作。
我使用Visio2003绘制的糖果机状态图,画得不太好,可能不是很标准,UML对于面向对象的软件设计很重要。
对应的Java代码如下:
//State.java package State; /* * 状态接口State */ public interface State { public void insertQuarter(); // 投入25分钱 public void ejectQuarter(); // 拒绝25分钱 public void turnCrank(); // 转动曲柄 public void dispense(); // 发放糖果 } //NoQuarterState.java package State; import State.GumballMachine; /* * 没有25分钱状态,实现了State接口 */ public class NoQuarterState implements State{ GumballMachine gumballMachine; public NoQuarterState(GumballMachine gumballMachine){ this.gumballMachine=gumballMachine; } // 投入25分钱 public void insertQuarter() { System.out.println("You insert a quarter"); gumballMachine.setState(gumballMachine.getHasQuarterState()); } // 拒绝25分钱 public void ejectQuarter() { System.out.println("You haven't insert a quarter"); } // 转动曲柄 public void turnCrank() { System.out.println("You turned crank,but you there's no quarter"); } // 发放糖果 public void dispense() { System.out.println("You need to pay first"); } } //HasQuarterState.java package State; import java.util.Random; import State.GumballMachine; /* * 有25分钱状态,实现了State接口 */ public class HasQuarterState implements State { Random randomWinner = new Random(System.currentTimeMillis()); //首先我们增加一个随机数产生器,产生10%赢的机 会 GumballMachine gumballMachine; public HasQuarterState(GumballMachine gumballMachine){ this.gumballMachine = gumballMachine; } // 投入25分钱 public void insertQuarter() { System.out.println("You can not insert anther quarter"); } // 拒绝25分钱 public void ejectQuarter() { System.out.println("Quarter returned"); gumballMachine.setState(gumballMachine.getNoQuarterState()); } // 转动曲柄 public void turnCrank() { System.out.println("You turned..."); int winner = randomWinner.nextInt(10); System.out.println("winner =" + winner); if((winner ==0) && (gumballMachine.getCount() > 1)) { gumballMachine.setState(gumballMachine.getWinnerState()); } else { gumballMachine.setState(gumballMachine.getSoldState()); } } // 发放糖果 public void dispense() { System.out.println("No gumball dispensed"); } } //SoldState.java package State; import State.GumballMachine; /* * 售出糖果状态,实现了State接口 */ public class SoldState implements State{ GumballMachine gumballMachine; public SoldState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } // 投入25分钱 public void insertQuarter() { System.out.println("Please wait, we're already giving you a gumball"); } // 拒绝25分钱 public void ejectQuarter() { System.out.println("Sorry,you have already turn crank"); } // 转动曲柄 public void turnCrank() { System.out.println("trun twice ,doesn't give you anthor gamball!"); } // 发放糖果 public void dispense() { gumballMachine.releaseBall(); if(gumballMachine.getCount()>0){ gumballMachine.setState(gumballMachine.getNoQuarterState()); } else { System.out.println("Opps,out of gamball!"); gumballMachine.setState(gumballMachine.getSoldOutState()); } } } //SoldOutState.java package State; import State.GumballMachine; /* * 通过售罄状态,实现了State接口 */ public class SoldOutState implements State{ GumballMachine gumballMachine; public SoldOutState(GumballMachine gumballMachine){ this.gumballMachine=gumballMachine; } // 投入25分钱 public void insertQuarter() { System.out.println("You can't insert a quarter, the machine is sold out"); } // 拒绝25分钱 public void ejectQuarter() { // TODO Auto-generated method stub System.out.println("You can't eject, you haven't inserted a quarter yet"); } // 转动曲柄 public void turnCrank() { // TODO Auto-generated method stub System.out.println("You turned, but there are no gumballs"); } // 发放糖果 public void dispense() { // TODO Auto-generated method stub System.out.println("No gumball dispensed"); } } //WinnerState.java package State; import State.GumballMachine; /* * 赢家状态,实现了State接口 */ public class WinnerState implements State{ GumballMachine gumballMachine; public WinnerState(GumballMachine gumballMachine){ this.gumballMachine = gumballMachine; } // 投入25分钱 @Override public void insertQuarter() { // TODO Auto-generated method stub System.out.println("Please wait, we're already giving you a gumball"); } // 拒绝25分钱 @Override public void ejectQuarter() { // TODO Auto-generated method stub System.out.println("Sorry,you have already turn crank"); } // 转动曲柄 @Override public void turnCrank() { // TODO Auto-generated method stub System.out.println("trun twice ,doesn't give you anthor gamball!"); } // 发放糖果 @Override public void dispense() { // TODO Auto-generated method stub System.out.println("You're a Winner! You get two gumballs for your quarter"); 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,out of gamball!"); gumballMachine.setState(gumballMachine.getSoldOutState()); } } } } //糖果机上下文环境类Java源文件 GumballMachine.java package State; import State.HasQuarterState; import State.NoQuarterState; import State.SoldOutState; import State.SoldState; import State.WinnerState; import State.State; /* * 糖果机器上下文环境接口类 GumballMachine */ public class GumballMachine { //状态实例 State soldOutState; State noQuarterState; State hasQuarterState; State soldState; State winnerState; // 实例变量state,初始化为糖果售罄状态 State state = soldOutState; // 记录机器内装有糖果的数目,开始机器是没有装糖果的 int count=0; // 构造器取得糖果的初始数目并把它放在一个实例变量count中 public GumballMachine(int numberGumballs) { // 每种状态都创建一个状态实例 soldOutState=new SoldOutState(this); noQuarterState=new NoQuarterState(this); hasQuarterState=new HasQuarterState(this); soldState=new SoldState(this); winnerState = new WinnerState(this); this.count = numberGumballs; // 若超过0颗糖果,就将状态设置为NoQuarterState if(numberGumballs > 0) { state = noQuarterState; } } // 取得机器内的糖果数目 public int getCount() { return count; } // 取得糖果售罄状态 public State getSoldOutState() { return soldOutState; } // 取得没有25分钱状态 public State getNoQuarterState() { return noQuarterState; } // 取得拥有25分钱 public State getHasQuarterState() { return hasQuarterState; } // 取得售出糖果状态 public State getSoldState() { return soldState; } // 取得赢家状态 public State getWinnerState() { return winnerState; } // 投入25分钱 public void insertQuarter(){ state.insertQuarter(); } // 拒绝25分钱 public void ejectQuarter(){ state.ejectQuarter(); } // 转动曲柄 public void turnCrank(){ state.turnCrank(); state.dispense(); } // 设置状态 public void setState(State state){ this.state=state; } // 糖果滚出来一个 public void releaseBall(){ System.out.println("A gumball comes rolling out of the solt..."); if(count!=0){ count--; } } } //测试糖果机的Java源文件 GumballMachineTestDrive.java package State; /* * 糖果机测试驱动程序:GumballMachineTestDrive.java */ public class GumballMachineTestDrive { /** * @param args */ public static void main(String[] args) { GumballMachine gumballMachine = new GumballMachine(5); System.out.println(gumballMachine); System.out.println("The current gumball number is:" + gumballMachine.getCount()); System.out.println("****************************************"); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); System.out.println(gumballMachine); System.out.println("The current gumball number is:" + gumballMachine.getCount()); System.out.println("****************************************"); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); System.out.println(gumballMachine); System.out.println("The current gumball number is:" + gumballMachine.getCount()); System.out.println("****************************************"); gumballMachine.insertQuarter(); gumballMachine.turnCrank(); System.out.println(gumballMachine); System.out.println("The current gumball number is:" + gumballMachine.getCount()); System.out.println("****************************************"); } }
运行结果截图如下:
对应的C++代码如下:
//State抽象基类 //State.h #pragma once class State { public: State(void); public: ~State(void); public: // 投入25分钱 virtual void insertQuarter(void)=0; public: // 退回25分钱 virtual void ejectQuarter(void)=0; public: // 转动曲柄 virtual void turnCrank(void)=0; public: // 发放糖果 virtual void dispense(void)=0; }; //State.cpp #include "State.h" State::State(void) { } State::~State(void) { } //没有25分钱状态类 NoQuarterState //NoQuarterState.h #pragma once #include "state.h" #include "GumballMachine.h" class NoQuarterState : public State { public: NoQuarterState(GumballMachine *pGumballMachine); public: ~NoQuarterState(void); public: // 投入25分钱 void insertQuarter(void); public: // 退回25分钱 void ejectQuarter(void); public: // 转动曲柄 void turnCrank(void); public: // 发放糖果 void dispense(void); private: // 糖果机实例变量 GumballMachine *m_pGumballMachine; }; //NoQuarterState.cpp #include "NoQuarterState.h" #include <iostream> using namespace std; NoQuarterState::NoQuarterState(GumballMachine *pGumballMachine) { this->m_pGumballMachine = pGumballMachine; } NoQuarterState::~NoQuarterState(void) { } // 投入25分钱 void NoQuarterState::insertQuarter(void) { cout<<"You inserted a quarter"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getHasQuarterState()); } // 退回25分钱 void NoQuarterState::ejectQuarter(void) { cout<<"You haven't inserted a quarter"<<endl; } // 转动曲柄 void NoQuarterState::turnCrank(void) { cout<<"You turned, but there's no quarter"<<endl; } // 发放糖果 void NoQuarterState::dispense(void) { cout<<"You need to pay first"<<endl; } //有25分钱状态 HasQuarterState //HasQuarterState.h #pragma once #include "state.h" #include "GumballMachine.h" class HasQuarterState : public State { public: HasQuarterState(GumballMachine *pGumballMachine); public: ~HasQuarterState(void); public: // 投入25分钱 void insertQuarter(void); public: // 退回25分钱 void ejectQuarter(void); public: // 转动曲柄 void turnCrank(void); public: // 发放糖果 void dispense(void); private: // 糖果机实例变量 GumballMachine *m_pGumballMachine; }; //HasQuarterState.cpp #include "HasQuarterState.h" #include <iostream> #include <cstdlib> #include <ctime> using namespace std; HasQuarterState::HasQuarterState(GumballMachine *pGumballMachine) { this->m_pGumballMachine = pGumballMachine; } HasQuarterState::~HasQuarterState(void) { } // 投入25分钱 void HasQuarterState::insertQuarter(void) { cout<<"You can't insert another quarter"<<endl; } // 退回25分钱 void HasQuarterState::ejectQuarter(void) { cout<<"Quarter returned"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getNoQuarterState()); } // 转动曲柄 void HasQuarterState::turnCrank(void) { cout<<"You turned..."<<endl; // srand(time(0)); //用时间作种子,使每次随即的数字不一样 //int winner = (int)(10.0*rand()/(RAND_MAX+1.0)); // 产生随机数 int winner = 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()); } } // 发放糖果 void HasQuarterState::dispense(void) { cout<<"No gumball dispensed"<<endl; } //售出糖果状态 SoldState //SoldState.h #pragma once #include "state.h" #include "GumballMachine.h" class SoldState : public State { public: SoldState(GumballMachine *pGumballMachine); public: ~SoldState(void); public: // 投入25分钱 void insertQuarter(void); // 退回25分钱 void ejectQuarter(void); // 转动曲柄 void turnCrank(void); // 发放糖果 void dispense(void); private: // 糖果机实例变量 GumballMachine *m_pGumballMachine; }; //SoldState.cpp #include "SoldState.h" #include <iostream> using namespace std; SoldState::SoldState(GumballMachine *pGumballMachine) { this->m_pGumballMachine = pGumballMachine; } SoldState::~SoldState(void) { } // 投入25分钱 void SoldState::insertQuarter(void) { cout<<"Please wait, we're already giving you a gumball"<<endl; } // 退回25分钱 void SoldState::ejectQuarter(void) { cout<<"Sorry, you already turned the Crank"<<endl; } // 转动曲柄 void SoldState::turnCrank(void) { cout<<"Turning twice doesn't get you another gumball!"<<endl; } // 发放糖果 void SoldState::dispense(void) { m_pGumballMachine->releaseBall(); if(m_pGumballMachine->getCount()>0) { m_pGumballMachine->setState(m_pGumballMachine->getNoQuarterState()); } else { cout<<"Oops, out of gumballs!"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getSoldOutState()); } } //糖果售罄状态 SoldOutState类 //SoldOutState.h #pragma once #include "state.h" #include "GumballMachine.h" class SoldOutState : public State { public: SoldOutState(GumballMachine *pGumballMachine); public: ~SoldOutState(void); public: // 投入25分钱 void insertQuarter(void); // 退回25分钱 void ejectQuarter(void); // 转动曲柄 void turnCrank(void); // 发放糖果 void dispense(void); private: // 糖果机实例变量 GumballMachine *m_pGumballMachine; }; //SoldOutState.cpp #include "SoldOutState.h" #include <iostream> using namespace std; SoldOutState::SoldOutState(GumballMachine *pGumballMachine) { this->m_pGumballMachine = pGumballMachine; } SoldOutState::~SoldOutState(void) { } // 投入25分钱 void SoldOutState::insertQuarter(void) { cout<<"You can't insert a quarter, the machine is sold out"<<endl; } // 退回25分钱 void SoldOutState::ejectQuarter(void) { cout<<"You can't eject, you haven't inserted a quarter yet"<<endl; } // 转动曲柄 void SoldOutState::turnCrank(void) { cout<<"You turned, but there are no gumballs"<<endl; } // 发放糖果 void SoldOutState::dispense(void) { cout<<"No gumball dispensed"<<endl; } //赢家状态 WinnerState类 //WinnerState.h #pragma once #include "state.h" #include "GumballMachine.h" class WinnerState : public State { public: WinnerState(GumballMachine *pGumballMachine); public: ~WinnerState(void); public: // 投入25分钱 void insertQuarter(void); public: // 退回25分钱 void ejectQuarter(void); public: // 转动曲柄 void turnCrank(void); public: // 发放糖果 void dispense(void); private: // 糖果机实例变量 GumballMachine *m_pGumballMachine; }; //WinnerState.cpp #include "WinnerState.h" #include <iostream> using namespace std; WinnerState::WinnerState(GumballMachine *pGumballMachine) { this->m_pGumballMachine = pGumballMachine; } WinnerState::~WinnerState(void) { } // 投入25分钱 void WinnerState::insertQuarter(void) { cout<<"Please wait, we're already giving you a gumball"<<endl; } // 退回25分钱 void WinnerState::ejectQuarter(void) { cout<<"Sorry, you already turned the Crank"<<endl; } // 转动曲柄 void WinnerState::turnCrank(void) { cout<<"Turning twice doesn't get you another gumball!"<<endl; } // 发放糖果 void WinnerState::dispense(void) { cout<<"You're a Winner! You get two gumballs for your quarter"; 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, out of gumballs!"<<endl; m_pGumballMachine->setState(m_pGumballMachine->getSoldOutState()); } } } //糖果机 上下文环境GumballMachine类 //GumballMachine.h #pragma once #include "State.h" class GumballMachine { public: GumballMachine(int numberGumballs=0); public: ~GumballMachine(void); private: // 状态类的指针 State* m_pState; private: // 记录机器内的糖果数目 int m_count; State* m_pSoldOutState; State* m_pNoQuarterState; State* m_pHasQuarterState; State* m_pSoldState; State* m_pWinnerState; public: void insertQuarter(void); public: // 退回25分钱 void ejectQuarter(void); public: // 转动曲柄 void turnCrank(void); public: // 设置状态 void setState(State* pState); public: // 释放糖果 void releaseBall(void); public: // 获取当前糖果的数目 int getCount(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> using namespace std; GumballMachine::GumballMachine(int numberGumballs) { m_pSoldOutState = new SoldOutState(this); m_pNoQuarterState = new NoQuarterState(this); m_pHasQuarterState = new HasQuarterState(this); m_pSoldState = new SoldState(this); this->m_count = numberGumballs; m_pState = m_pSoldOutState; if(numberGumballs>0) { m_pState = m_pNoQuarterState; } } GumballMachine::~GumballMachine(void) { delete m_pSoldOutState; delete m_pNoQuarterState; delete m_pHasQuarterState; delete m_pSoldState; } void GumballMachine::insertQuarter(void) { m_pState->insertQuarter(); } // 退回25分钱 void GumballMachine::ejectQuarter(void) { m_pState->ejectQuarter(); } // 转动曲柄 void GumballMachine::turnCrank(void) { m_pState->turnCrank(); m_pState->dispense(); } // 设置状态 void GumballMachine::setState(State* pState) { this->m_pState = pState; } // 释放糖果 void GumballMachine::releaseBall(void) { cout<<"A gumball comes rolling out of the solt..."; if(m_count != 0) { m_count = m_count -1; } } // 获取当前糖果的数目 int GumballMachine::getCount(void) { return m_count; } // 获取发放糖果状态 State* GumballMachine::getSoldState(void) { return m_pSoldState; } // 获取拥有25分钱状态 State* GumballMachine::getHasQuarterState(void) { return m_pHasQuarterState; } // 获取没有25分钱状态 State* GumballMachine::getNoQuarterState(void) { return m_pNoQuarterState; } // 获取糖果售罄状态 State* GumballMachine::getSoldOutState(void) { return m_pSoldOutState; } // 获取赢家状态 State* GumballMachine::getWinnerState(void) { return m_pWinnerState; } //测试主函数文件 TestDriver.cpp #include "GumballMachine.h" #include <iostream> using namespace std; int main() { srand(time(NULL)); //以系统时间作为种子,设置随机数种子
GumballMachine *pGumballMachine = new GumballMachine(5); pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl; pGumballMachine->insertQuarter(); pGumballMachine->turnCrank(); cout<<"the gumball count is:"<<pGumballMachine->getCount()<<endl; return 0; }
下面是程序运行结果截图:
记得以前在学校学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封装旋转门能做的所有操作 */ class TurnstileController { public void unlock(){ System.out.println("正在执行开门操作…"); } public void alarm(){ System.out.println("注意! 有人强行越过旋转门…"); } public void lock(){ System.out.println("正在执行关门操作…"); } public void refund(){ System.out.println("退款中…"); } } /* *Turnstile:旋转门类 */ class Turnstile { //用来代表状态的两个常量 public static final int LOCKED = 0; public static final int UNLOCKED = 1; //用来代表事件的常量 public static final int COIN = 0; public static final int PASS = 1; //当前旋转门的状态 public int state = LOCKED; public TurnstileController tController; public Turnstile(TurnstileController tController){ this.tController = tController; } //当新的事件发生时调用此方法,同时把事件代码传递给它 public void eventHappen(int event){ switch(state){ case LOCKED: switch(event){ case COIN: tController.unlock(); state = UNLOCKED; break; case PASS: tController.alarm(); break; } break; case UNLOCKED: switch(event){ case COIN: tController.refund(); break; case PASS: tController.lock(); state = LOCKED; break; } break; } } } public class TurnstileTest { public static void main(String [] args){ Turnstile turnstile = new Turnstile(new TurnstileController()); 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的请求,每一个具体状态实现了在该状态下,针对某一事件的特定响应动作和下一步的状态迁移 |
上面这幅图来源于<<Head First设计模式>>的状态模式章节。
代码如下:
interface State{ public void someEventHappen(Context c); } class StateA implements State{ public void someEventHappen(Context c){ c.actionA(); c.state = new StateB(); } } class StateB implements State{ public void someEventHappen(Context c){ c.actionB(); c.state = new StateA(); } } class Context{ public State state = new StateA(); public void someEventHappen(){ state.someEventHappen(this); } public void actionA(){ System.out.println("action A is going on..."); } public void actionB(){ System.out.println("aciton B is going on..."); } } public class StateTest{ public static void main(String [] args){ Context c = new Context(); c.someEventHappen(); c.someEventHappen(); } }
注意该代码实现了如下的状态机:
你的任务:
参考以上描述的状态模式,利用状态模式重新设计并编写“地铁十字旋转门(turnstile)”问题。
下面是我的Java实现代码,不知道对不对。
//MyTurstileTest.java interface State{ public abstract void DropCoinEventHappen(Context c); public abstract void PassEventHappen(Context c); } class Context { private State state = new LockedState(); public void CoinEventHappen(){ state.DropCoinEventHappen(this); } public void PassEventHappen(){ state.PassEventHappen(this); } public void unlock(){ System.out.println("正在执行开门操作......."); state = new UnLockedState(); } public void alarm(){ System.out.println("注意! 有人强行越过旋转门......."); state = new LockedState(); } public void lock(){ System.out.println("正在执行关门操作........"); state = new LockedState(); } public void refund(){ System.out.println("退款中........"); state = new UnLockedState(); } } class LockedState implements State{ public void DropCoinEventHappen(Context c){ c.unlock();//执行开门操作 } public void PassEventHappen(Context c){ c.alarm();//报警 } } class UnLockedState implements State{ public void DropCoinEventHappen(Context c){ c.refund();//退款 } public void PassEventHappen(Context c){ c.lock();//执行关门操作 } } public class MyTurstileTest{ public static void main(String[] args){ Context c = new Context(); System.out.println("地铁十字旋转门初始态为关的状态......"); //起始状态地铁十字旋转门(turnstile)默认处于关的状态 c.CoinEventHappen(); //turnstile状态为关时,发生投币操作,事件发生后turnstile状态为开 c.PassEventHappen(); //turnstile状态为开时,发生人员通过事件,事件发生后turnstile状态为关 c.PassEventHappen(); //turnstile状态为关时,发生人员通过事件,事件发生后turnstile状态为开 c.CoinEventHappen(); //turstile状态为关时,发生投币操作,事件发生后turnstile状态为开 } }
下面是程序运行代码运行结果的贴图
另外我想使用MFC结合状态模式和工厂模式做一个标准版的Windows计算器,大概分成左操作数状态、操作符状态、右操作数状态、结果状态、错误异常状态这5个状态,然后可能还要区分单目运算符和双目运算符等等,等我做完这个练习后把关键的状态图和C++相关类设计代码也传上来,算是对状态模式学习的一个总结吧。