天天看点

C++设计模式十三--StatePattern(状态模式)

定义

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

要点

1.状态模式允许一个对象基于内部状态而拥有不同的行为。

  2.和程序状态机(PSM)不同,状态模式用类代表状态。

  3.Context会将行为委托给当前状态对象。

  4.通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。

  5.状态模式和策略模式有相同的类图,但它们的意图不同。

  6.**策略模式**通常会用行为或算法来配置Context类,而状态模式允许Context随着状态的改变而改变行为。

  7.状态可以有State类或者Context类控制。

  8.使用状态模式通常会导致设计中类的数目大量增加。

  9.状态类可以被多个Context示例共享。

类图

C++设计模式十三--StatePattern(状态模式)

Context:它拥有一些内部状态。当有人调用request()方法时,它就会被委托到状态来处理(state->handle())。

State:状态接口,所有状态都需要实现这个接口,这样一来,状态之间可以互相替换。

ConcreteStateA/ConcreteStateB:具体状态,可以有很多。处理来自Context的请求。每个ConcreteState都提供了它自己对于请求的实现。所以当Context改变状态时行为也跟着改变。

示例

下面通过实现一个糖果自动售货机,其中状态图如下所示:

C++设计模式十三--StatePattern(状态模式)

State.h

#ifndef STATE_H
#define STATE_H

#include <iostream>

namespace StatePattern {

using std::cout;
using std::endl;

class GumballMachine;

class State {
public:
	State(){}
	virtual ~State(){}

	virtual void insertQuarter() = 0;
	virtual void ejectQuarter() = 0;
	virtual void turnCrank() = 0;
	virtual void dispense() = 0;		
};

// 未投入硬币
class NoQuarterState : public State {
private:
	GumballMachine* m_gumballMachine;
public:
	NoQuarterState(GumballMachine* gumballMachine);
	virtual ~NoQuarterState();

	void insertQuarter();
	void ejectQuarter();
	void turnCrank();
	void dispense();
};

// 投入硬币
class HasQuarterState : public State {
private:
	GumballMachine* m_gumballMachine;
public:
	HasQuarterState(GumballMachine* gumballMachine);
	virtual ~HasQuarterState();

	void insertQuarter();
	void ejectQuarter();
	void turnCrank();
	void dispense();
};

// 准备出售糖果
class SoldState : public State {
private:
	GumballMachine* m_gumballMachine;
public:
	SoldState(GumballMachine* gumballMachine);
	virtual ~SoldState();

	void insertQuarter();
	void ejectQuarter();
	void turnCrank();
	void dispense();
};

// 糖果售罄
class SoldOutState : public State {
private:
	GumballMachine* m_gumballMachine;
public:
	SoldOutState(GumballMachine* gumballMachine);
	virtual ~SoldOutState();

	void insertQuarter();
	void ejectQuarter();
	void turnCrank();
	void dispense();
};

class WinnerState : public State {
private:
	GumballMachine* m_gumballMachine;
public:
	WinnerState(GumballMachine* gumballMachine);
	virtual ~WinnerState();

	void insertQuarter();
	void ejectQuarter();
	void turnCrank();
	void dispense();
};

}

#endif
           

State.cpp

#include "State.h"
#include "GumballMachine.h"

using namespace StatePattern;

NoQuarterState::NoQuarterState(GumballMachine* gumballMachine)
{
	this->m_gumballMachine = gumballMachine;
}
NoQuarterState::~NoQuarterState(){}

void NoQuarterState::insertQuarter()
{
	cout << "You inserted a quarter" << endl;
	m_gumballMachine->setState(m_gumballMachine->getHasQuarterState());
}
void NoQuarterState::ejectQuarter()
{
	cout << "You haven't inserted a quarter..." << endl;
}
void NoQuarterState::turnCrank()
{
	cout << "YOu turned, but there's no quarter" << endl;
}
void NoQuarterState::dispense()
{
	cout << "You need to pay first" << endl;
}		



HasQuarterState::HasQuarterState(GumballMachine* gumballMachine)
{
	this->m_gumballMachine = gumballMachine;
}
HasQuarterState::~HasQuarterState()
{

}
void HasQuarterState::insertQuarter()
{
	cout << "You can't insert another quarter" << endl;
}
void HasQuarterState::ejectQuarter()
{
	cout << "Quarter returned" << endl;
	m_gumballMachine->setState(m_gumballMachine->getNoQuarterState());
}
void HasQuarterState::turnCrank()
{
	cout << "You turned..." << endl;
	m_gumballMachine->setState(m_gumballMachine->getSoldState());
}
void HasQuarterState::dispense()
{
	cout << "No gumball dispensed" << endl;
}	



SoldState::SoldState(GumballMachine* gumballMachine)
{
	this->m_gumballMachine = gumballMachine;
}
SoldState::~SoldState(){}

void SoldState::insertQuarter()
{
	cout << "Please wait, we're already giving you a gumball" << endl;
}
void SoldState::ejectQuarter()
{
	cout << "Sorry, you alread turned the crank" << endl;
}
void SoldState::turnCrank()
{
	cout << "Turning twice doesn't get you another gumball" << endl;
}
void SoldState::dispense()
{
	m_gumballMachine->releaseBall();
	if (m_gumballMachine->getCount() > 0) {
		m_gumballMachine->setState(m_gumballMachine->getNoQuarterState());
	} else {
		cout << "Oops, out of gumballs" << endl;
		m_gumballMachine->setState(m_gumballMachine->getSoldOutState());
	}
}	
		

SoldOutState::SoldOutState(GumballMachine* gumballMachine)
{
	this->m_gumballMachine = gumballMachine;
}
SoldOutState::~SoldOutState(){}

void SoldOutState::insertQuarter()
{
	cout << "You can't insert a quarter, the machine is sold out" << endl;
}
void SoldOutState::ejectQuarter()
{
	cout << "You can't eject, you haven't inserted a quarter yet" << endl;
}
void SoldOutState::turnCrank()
{
	cout << "You turned, but there are no gumballs" << endl;
}
void SoldOutState::dispense()
{
	cout << "No gumball dispensed" << endl;
}


WinnerState::WinnerState(GumballMachine* gumballMachine)
{
	this->m_gumballMachine = gumballMachine;
}
WinnerState::~WinnerState(){}

void WinnerState::insertQuarter()
{

}
void WinnerState::ejectQuarter()
{

}
void WinnerState::turnCrank()
{

}
void WinnerState::dispense()
{
	
}				
           

GumballMachine.h

#ifndef GUMBALLMACHINE_H
#define GUMBALLMACHINE_H

#include "State.h"

namespace StatePattern {

class GumballMachine 
{
private:
	State* m_soldOutState;
	State* m_noQuarterState;
	State* m_hasQuarterState;
	State* m_soldState;

	State* m_state;
	int count;

public:
	GumballMachine(int numberGumballs = 0)
	{
		m_soldOutState = new SoldOutState(this);
		m_noQuarterState = new NoQuarterState(this);
		m_hasQuarterState = new HasQuarterState(this);
		m_soldState = new SoldState(this);

		this->count = numberGumballs;
		m_state = m_soldOutState;

		if (numberGumballs > 0) {
			m_state = m_noQuarterState;
		}
	}	
	~GumballMachine(){}
	void insertQuarter()	// 放入硬币
	{
		m_state->insertQuarter();
	}
	void ejectQuarter()		// 退钱
	{
		m_state->ejectQuarter();
	}
	void turnCrank()		// 转动曲柄,拿到糖果
	{
		m_state->turnCrank();
		m_state->dispense();
	}
	void setState(State* state)
	{
		this->m_state = state;
	}
	void releaseBall()
	{
		cout << "A gumball comes rolling out the slot..." << endl;
		if (0 != count) {
			count --;
		}
	}
	void refill(int numberGumballs) 
	{
		this->count = numberGumballs;
		if (numberGumballs > 0) {
			m_state = m_noQuarterState;
		}
	}

	State* getSoldOutState()
	{
		return m_soldOutState;
	}
	State* getNoQuarterState()
	{
		return m_noQuarterState;
	}
	State* getHasQuarterState()
	{
		return m_hasQuarterState;
	}
	State* getSoldState()
	{
		return m_soldState;
	}
	int getCount()
	{
		return count;
	}
};

}

#endif

           

main.cpp

#include "GumballMachine.h"

using namespace StatePattern;

int main()
{
	GumballMachine* gumballMachine = new GumballMachine(1);

	gumballMachine->insertQuarter();
	gumballMachine->turnCrank();

	gumballMachine->turnCrank();

	delete gumballMachine;
}
           

测试

测试结果如下图所示:

C++设计模式十三--StatePattern(状态模式)

继续阅读