大话设计模式 —— 第十六章《状态模式》C++ 代码实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/89364783

目录

定义

优点

缺点

使用场景


状态模式是一种行为型设计模式。当某个对象在不同状态下有不同行为时使用,在该模式中,我们将对象的不同状态 
定义成不同的类,在这些状态类下有它们各自的行为,然后在客户端调用 Context 类,而不需要显示地去设置各个状态之间的转换


定义


  • 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

该模式的本质是对象的状态改变时,会引起其行为的改变,从外部看就像该对象所对应的类的行为发生了改变一样。例如,电灯的开关,在灯的不同状态下(亮或灭),按下开关时,灯的行为是不一样的。或者说汽车,只有在车停下的时候才能打开车门,行驶的时候是不可以开门的。这就是状态的不同就会导致不同的行为。

状态模式UML图
  • 从UML来看,UML的结构似乎和策略模式是一模一样的,但是两种模式的本质却是完全不同的。策略模式中的策略(或者说是行为)是因为根据外界需要而使用不同的策略来完成需求;而状态模式中,是因为其自身状态改变,而影响了自身的一系列行为的改变。虽然这个状态的变更可能是外界引发的。
  • 抽象状态角色(State),负责定义各个状态有哪些行为,该抽象状态包含所有具体状态的方法。并且封装环境角色,帮助切换状态。
  • 具体状态角色(ConcreteState),实现具体状态下可以执行的行为,    每一个具体状态类必须完成两个职责:该类本状态下要做的事情,以及如何执行到其他具体状态类的状态。
  • 环境角色(Context) ,该角色是客户端要调用的接口,在该类内部维护一个ConcreteState子类的一个实例,可以负责具体状态的切换(客户端不知道状态的切换)。

用C++ 代码实现大话设计模式本章代码:

#include<iostream>
using namespace std;

class State;
class ForenoonState;
class NoonState;
class AfternonnState;
class EveningState;
class SleepingState;
class RestState;
class Work;

// 抽象状态角色,负责定义各个状态有哪些行为,该抽象状态包含所有具体状态的方法。并且封装环境角色,帮助切换状态。
class State 
{
public:
	virtual void writeprogram(Work* w) = 0;
	virtual ~State() = default;
};
// Contex 角色,在该类内部维护一个ConcreteState子类的一个实例,可以负责具体状态的切换
class Work
{
private:
	State* current;
	double m_hour;
	bool m_finish = false;
public:
	Work();
	~Work();
	void setHour(double hour) { m_hour = hour; }
	double getHour() { return m_hour; }

	void setFinish(bool finish) { m_finish = finish; }
	bool getFinish() { return m_finish; }
	void SetState(State* s)
	{
		delete current;
		current = s;
	}
	void WorkProgram()
	{
		current->writeprogram(this);
	}
};

// 下面都是具体的状态类,每一个具体状态类必须完成两个职责:该类本状态下要做的事情,以及如何执行到其他具体状态类的状态。
class ForenoonState :public State
{
public:
	void writeprogram(Work* w)override;
};

class NoonState :public State
{
public:
	void writeprogram(Work* w)override;
};

class AfternoonState :public State
{
public:
	void writeprogram(Work* w)override;
};

class EveningState :public State
{
public:
	void writeprogram(Work* w)override;
};

class SleepingState :public State
{// 睡眠状态
public:
	void writeprogram(Work *w)override;
	
};

class RestState :public State
{// 下班休息状态
public:
	void writeprogram(Work *w)override;
	
};

Work::Work()
{
	current = new ForenoonState();
}
Work::~Work()
{
	delete current;
}

void ForenoonState::writeprogram(Work* w)
{
	if (w->getHour() < 12)
	{
		cout << "当前时间:" << w->getHour() << "点,上午工作,精神百倍" << endl;
	}
	else
	{
		w->SetState(new NoonState());
		w->WorkProgram();
	}
}

void NoonState::writeprogram(Work* w)
{
	if (w->getHour() < 13)
	{
		cout << "当前时间:" << w->getHour() << "点,吃午饭,睡午觉" << endl;
	}
	else
	{
		w->SetState(new AfternoonState());
		w->WorkProgram();
	}
}

void AfternoonState::writeprogram(Work* w)
{
	if (w->getHour() < 17)
	{
		cout << "当前时间:" << w->getHour() << "点,下午状态还不错" << endl;
	}
	else
	{
		w->SetState(new EveningState());
		w->WorkProgram();
	}
}

void EveningState::writeprogram(Work* w)
{
	if (w->getFinish())
	{
		w->SetState(new RestState());
		w->WorkProgram();
	}
	else
	{
		if (w->getHour() < 21)
		{
			cout << "当前时间:" << w->getHour() << "点,加班哦,疲惫至极 " << endl;
		}
		else
		{
			w->SetState(new SleepingState());
			w->WorkProgram();
		}
	}
}

void SleepingState::writeprogram(Work *w)
{
	cout << "当前时间:" << w->getHour() << "点,不行了,睡着了 " << endl;
}

void RestState::writeprogram(Work *w)
{
	cout << "当前时间:" << w->getHour() << "点,下班回家了 " << endl;
}

int main()
{
	Work emergencyProjects;

	emergencyProjects.setHour(9);
	emergencyProjects.WorkProgram();

	emergencyProjects.setHour(10);
	emergencyProjects.WorkProgram();

	emergencyProjects.setHour(12);
	emergencyProjects.WorkProgram();

	emergencyProjects.setHour(13);
	emergencyProjects.WorkProgram();

	emergencyProjects.setHour(14);
	emergencyProjects.WorkProgram();

	emergencyProjects.setHour(17);
	emergencyProjects.WorkProgram();

	emergencyProjects.setFinish(false);

	emergencyProjects.setHour(19);
	emergencyProjects.WorkProgram();

	emergencyProjects.setHour(22);
	emergencyProjects.WorkProgram();

	system("pause");
	return 0;
}

运行后截图:

可以看到,在客户端代码中,我们只需要调用Context类中方法即可,并不需要手动去改变状态,每执行一次方法就可以自动改变对象的状态,进而可以产生不同的行为,这就是状态模式。 


优点


  • 通过把各种状态判断逻辑分布到State的子类中,减少相互之间的依赖

在状态模式中,环境(Context)中不必出现大量的条件判断语句。环境(Context)实例所呈现的状态变得更加清晰、容易理解,提高代码的可维护性。

  • 如果不是有状态模式,一个对象需要在不同状态执行不同方法或者拥有不同特性的话,你可能需要在大量的 switch...case 或者 if...else 语句来根据不同状态执行不同方法,代码看起来就很复杂了

遵循设计原则

  • 每一个状态都是一个子类,符合单一职责原则,且当需要增加一个状态时,也是可以增加一个子类,需要修改一个状态时,也是修改一个子类即可。
  • 所有的状态都是一个子类,如果修改状态,只需要修改这个状态的子类即可,符合单一职责原则。且当需要增加一个状态时,也增加一个子类即可;需要修改一个状态时,也是修改一个子类即可。

封装性好

  • 状态的变换放置在类的内部实现,外界调用不知道内部的状态改变,只要调用其方法即可。

缺点


  • 由于所有的状态都是一个类,有的对象可能会有非常多的状态。随着状态的增加,系统类和对象个数也会增加。这个时候就使用状态模式就会导致类特别多,结构和实现会比较复杂,且不利于维护。如果使用不当将导致程序结构和代码的混乱。所以说,在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
  • 状态模式对”开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

使用场景


  • 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。
  • 需要编写大量的条件分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态。

猜你喜欢

转载自blog.csdn.net/qq_34536551/article/details/89364783
今日推荐