您的位置:首页 > 其它

<<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代码如下:

//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++相关类设计代码也传上来,算是对状态模式学习的一个总结吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: