UML类图(仅供参考)如下:
状态模式解决的问题:
对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为,这个状态的判断不需要放在一个类中,而是在一系列类中判断,并且把这些行为在不同的多态中实现
源码
#include <list>
class CContext;
// 抽象状态类
// 用来处理工作类的一种状态
class CStatus
{
public:
virtual ~CStatus() {}
// 判断工作类的状态标识是否满足本对象规定的条件
// 满足就执行一些事情,否则就更换下一个状态对象的条件再判断
virtual void Handle(CContext *pContext) = 0;
};
// 具体状态类A
class CConcreteStatusA :public CStatus
{
public:
virtual void Handle(CContext *pContext);
};
// 具体状态类B
class CConcreteStatusB :public CStatus
{
public:
virtual void Handle(CContext *pContext);
};
// 具体状态类C
class CConcreteStatusC :public CStatus
{
public:
virtual void Handle(CContext *pContext);
};
// 具体的工作类
class CContext
{
public:
CContext(CStatus *pStatus) :m_pStatus(pStatus), m_pNextStatus(NULL) {}
~CContext();
// 执行工作
void Request();
// 添加下一个状态对象
void SetStatus(CStatus *pStatus);
// 设置当前状态标识
void SetFlag(const int nFlag);
int GetFlag() const;
protected:
// 清理工作中创建的状态处理对象
// 必须在每次调用Request后调用
void ClearStatus();
private:
// 状态对象链表
std::list<CStatus *> m_listStatus;
// 初始状态对象
CStatus * const m_pStatus;
// 下一个状态对象
CStatus *m_pNextStatus;
// 描述当前工作类的一种标识
int m_nFlag;
};
#include "Status.h"
#include <iostream>
#include <algorithm>
void CConcreteStatusA::Handle(CContext *pContext)
{
if (pContext->GetFlag() < 10)
{
std::cout << "现在我们应该去上学" << std::endl;
}
else
{
pContext->SetStatus(new CConcreteStatusB());
pContext->Request();
}
}
void CConcreteStatusB::Handle(CContext *pContext)
{
if ((10 <= pContext->GetFlag()) && (pContext->GetFlag() < 12))
{
std::cout << "现在我们应该在上课" << std::endl;
}
else
{
pContext->SetStatus(new CConcreteStatusC());
pContext->Request();
}
}
void CConcreteStatusC::Handle(CContext *pContext)
{
if (pContext->GetFlag() >= 12)
{
std::cout << "现在我们应该在玩耍" << std::endl;
}
}
CContext::~CContext()
{
delete m_pStatus;
}
void CContext::Request()
{
bool bFlag = false;
if (NULL == m_pNextStatus)
{
m_pNextStatus = m_pStatus;
bFlag = true;
}
else
{
// 获取刚刚创建的状态对象
auto it = m_listStatus.end();
m_pNextStatus = *(--it);
}
m_pNextStatus->Handle(this);
if (bFlag)ClearStatus();
}
void CContext::ClearStatus()
{
for (auto var : m_listStatus)
{
delete var;
}
m_listStatus.clear();
m_pNextStatus = NULL;
}
void CContext::SetStatus(CStatus *pStatus)
{
m_listStatus.push_back(pStatus);
}
void CContext::SetFlag(const int nFlag)
{
m_nFlag = nFlag;
}
int CContext::GetFlag() const
{
return m_nFlag;
}
int main()
{
CContext *pContext = new CContext(new CConcreteStatusA());
pContext->SetFlag(10);
pContext->Request();
pContext->SetFlag(9);
pContext->Request();
pContext->SetFlag(11);
pContext->Request();
pContext->SetFlag(12);
pContext->Request();
pContext->SetFlag(21);
pContext->Request();
delete pContext;
pContext = NULL;
}
好处
1、封装了转换规则
2、枚举可能的状态,在枚举状态之前需要确定状态种类
3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为
4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数