C++状态模式(State)

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、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值