设计模式(C++实现)(九)——状态模式

示例问题:

篮球运动员在比赛的时候,会因为体力、情绪等影响竞技状态。比如,刚上场的时候,体力充沛、动作灵活、投篮神准;打了8分钟过后,身体疲惫、动作变慢;下场休息3分钟并喝了一瓶红牛过后,体力恢复、恢复了运动能力和投篮手感;最后决胜3分钟,比分犬牙交错,肌肉紧张、身体匹配、精神兴奋。编写程序,描述各个状态下,运动员的情况。

分析:

如果创建一个篮球运动员类,在该类中实现一个展示运动员情况的函数,则该函数需要实现不同状态下篮球运动员情况,则该函数内容过多,如果出现新的情况,修改该函数带来较多风险。如何避免?能否将不同状态下,运动员的情况从运动员类中剥离出来,做到代码的责任分解?

解决方案:

State.h

在该文件中实现了状态的基类IState,及其子类CGameBeginState(比赛刚开始的状态)、CAfter8MinState(打了8分钟之后的状态)、CRestAndDrinkState(下场休息3分钟并喝了一瓶红牛之后的状态)、CLast3MinState(最后决胜3分钟的状态)。还有运动员类CBasketballPlayer。将运动员在不同状态的情况,分离出来,在状态类中实现,且将状态的判断在子类实现。

#pragma once

#include <iostream>

/*篮球运动员在比赛的时候,会因为体力、情绪等影响竞技状态。
比如,刚上场的时候,体力充沛、动作灵活、投篮神准;
打了8分钟过后,身体疲惫、动作变慢;
下场休息3分钟并喝了一瓶红牛过后,体力恢复、恢复了运动能力和投篮手感;
最后决胜3分钟,比分犬牙交错,肌肉紧张、身体匹配、精神兴奋。
编写程序,描述各个状态下,运动员的情况。*/

class CBasketballPlayer;

//状态基类
class IState
{
public:
	IState()
	: m_pState(nullptr)
	{

	}

	virtual ~IState()
	{

	}

	virtual void ShowAbility(CBasketballPlayer* pBasketballPlayer) = 0;

	IState* m_pState;
};

//比赛刚开始的状态
class CGameBeginState : public IState
{
public:
	CGameBeginState();

	virtual ~CGameBeginState();

	void ShowAbility(CBasketballPlayer* pBasketballPlayer);
};

//打了8分钟之后的状态
class CAfter8MinState : public IState
{
public:
	CAfter8MinState();

	virtual ~CAfter8MinState();

	void ShowAbility(CBasketballPlayer* pBasketballPlayer);
};

//下场休息3分钟并喝了一瓶红牛之后的状态
class CRestAndDrinkState : public IState
{
public:
	CRestAndDrinkState();

	virtual ~CRestAndDrinkState();

	void ShowAbility(CBasketballPlayer* pBasketballPlayer);
};

//最后决胜3分钟的状态
class CLast3MinState : public IState
{
public:
	CLast3MinState();

	virtual ~CLast3MinState();

	void ShowAbility(CBasketballPlayer* pBasketballPlayer);
};

//篮球运动员
class CBasketballPlayer
{
public:
	CBasketballPlayer()
	: m_iTime(0)
	, m_pState(nullptr)
	{
		m_pState = new(std::nothrow) CGameBeginState();//设置初始状态
	}

	virtual ~CBasketballPlayer()
	{
		if (nullptr != m_pState)
		{
			delete m_pState;
			m_pState = nullptr;
		}
	}

	void SetTime(int iTime)
	{
		m_iTime = iTime;
	}

	int GetTime()
	{
		return m_iTime;
	}

	void SetState(IState* pState)
	{
		m_pState = pState;
	}

	void Play()
	{
		if (nullptr != m_pState)
		{
			m_pState->ShowAbility(this);
		}
	}

private:
	int m_iTime;
	IState* m_pState;
};

State.cpp

#include "state.h"

CGameBeginState::CGameBeginState()
{
	m_pState = new(std::nothrow) CAfter8MinState();
}

CGameBeginState::~CGameBeginState()
{
	if (nullptr != m_pState)
	{
		delete m_pState;
		m_pState = nullptr;
	}
}

void CGameBeginState::ShowAbility(CBasketballPlayer* pBasketballPlayer)
{
	if (nullptr == pBasketballPlayer)
	{
		return;
	}
	if (pBasketballPlayer->GetTime() < 8)
	{
		std::cout << "体力充沛、动作灵活、投篮神准" << std::endl;
	}
	else
	{
		pBasketballPlayer->SetState(m_pState);
		pBasketballPlayer->Play();
	}
}

CAfter8MinState::CAfter8MinState()
{
	m_pState = new(std::nothrow) CRestAndDrinkState();
}

CAfter8MinState::~CAfter8MinState()
{
	if (nullptr != m_pState)
	{
		delete m_pState;
		m_pState = nullptr;
	}
}

void CAfter8MinState::ShowAbility(CBasketballPlayer* pBasketballPlayer)
{
	if (pBasketballPlayer->GetTime() < 11)
	{
		std::cout << "身体疲惫、动作变慢" << std::endl;
	}
	else
	{
		pBasketballPlayer->SetState(m_pState);
		pBasketballPlayer->Play();
	}
}

CRestAndDrinkState::CRestAndDrinkState()
{
	m_pState = new(std::nothrow) CLast3MinState();
}

CRestAndDrinkState::~CRestAndDrinkState()
{
	if (nullptr != m_pState)
	{
		delete m_pState;
		m_pState = nullptr;
	}
}

void CRestAndDrinkState::ShowAbility(CBasketballPlayer* pBasketballPlayer)
{
	if (pBasketballPlayer->GetTime() < 45)
	{
		std::cout << "体力恢复、恢复了运动能力和投篮手感" << std::endl;
	}
	else
	{
		pBasketballPlayer->SetState(m_pState);
		pBasketballPlayer->Play();
	}
}

CLast3MinState::CLast3MinState()
{

}

CLast3MinState::~CLast3MinState()
{

}

void CLast3MinState::ShowAbility(CBasketballPlayer* pBasketballPlayer)
{
	if (pBasketballPlayer->GetTime() < 48)
	{
		std::cout << "肌肉紧张、身体疲惫、精神兴奋" << std::endl;
	}
	else
	{
		std::cout << "比赛结束" << std::endl;
	}
}

main.cpp

// main.cpp : Defines the entry point for the console application.
//

#include "State.h"


int main()
{
	CBasketballPlayer BasketballPlayer;

	std::cout << "刚上场的时候:";
	BasketballPlayer.SetTime(1);
	BasketballPlayer.Play();

	std::cout << "打了8分钟过后:";
	BasketballPlayer.SetTime(9);
	BasketballPlayer.Play();

	std::cout << "下场休息3分钟并喝了一瓶红牛过后:";
	BasketballPlayer.SetTime(13);
	BasketballPlayer.Play();

	std::cout << "最后决胜3分钟:";
	BasketballPlayer.SetTime(46);
	BasketballPlayer.Play();

	std::cout << "比赛结束:";
	BasketballPlayer.SetTime(49);
	BasketballPlayer.Play();

	system("pause");
    return 0;
}

运行结果

状态模式的使用:

状态模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没有必要用“状态模式”了。

状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。

状态模式消除了庞大的条件分支语句,把各个状态转移逻辑分部到State的子类之间,来减少互相间的依赖。

何时使用状态模式:

当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为,且它的状态较多,判断复杂时就可以考虑使用状态模式了。

 

返回目录:设计模式(C++实现)(总)

上一篇:设计模式(C++实现)(八)——模板方法模式

下一篇:设计模式(C++实现)(十)——备忘录模式

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值