定义
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
要点
1.状态模式允许一个对象基于内部状态而拥有不同的行为。
2.和程序状态机(PSM)不同,状态模式用类代表状态。
3.Context会将行为委托给当前状态对象。
4.通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。
5.状态模式和策略模式有相同的类图,但它们的意图不同。
6.**策略模式**通常会用行为或算法来配置Context类,而状态模式允许Context随着状态的改变而改变行为。
7.状态可以有State类或者Context类控制。
8.使用状态模式通常会导致设计中类的数目大量增加。
9.状态类可以被多个Context示例共享。
类图
Context:它拥有一些内部状态。当有人调用request()方法时,它就会被委托到状态来处理(state->handle())。
State:状态接口,所有状态都需要实现这个接口,这样一来,状态之间可以互相替换。
ConcreteStateA/ConcreteStateB:具体状态,可以有很多。处理来自Context的请求。每个ConcreteState都提供了它自己对于请求的实现。所以当Context改变状态时行为也跟着改变。
示例
下面通过实现一个糖果自动售货机,其中状态图如下所示:
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;
}
测试
测试结果如下图所示: