这是个人学习编程模式的系列学习笔记第六篇。
采用Qt Creator进行编写,但尽量采用C++基础语法。
状态模式(Stat Pattern):允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
这种模式主要是用于处理两类情况:
1、有大量的ifelseif的判断,这样的写法不利于代码的维护和修改,如果有新的修改,对一大片这样的判断代码进行修改,容易引入新的问题。
2、有类似状态机这样的业务场景,根据不同的状态,需要执行不同的操作。
比较典型的例子是TCP协议连接。对TCP连接发起指令时,根据当期TCP连接的状态,会执行不同的处理。
个人理解,通过将一个具有复杂判断行为的方法,通过根据不同判断条件(或者状态),将不同的处理方式封装为独立的类,这样就可以保持代码的封闭-开发原则,并每个方法聚焦于单一任务。
在具体实现上,可设计一个状态抽象类作为接口,然后派生各个状态下的子类,每个子类只处理自己状态下的情况。然后定义一个上下文(context)类,这个类负责状态的切换和对应状态子类方法的调用。
场景描述
设想有一个农场主,在不同的季节干不同的活。一年有四季,春季播种,夏季浇水,秋季收获,冬季休息。3、4、5月是春季,6、7、8月是夏季,9、10、11月是秋季,12、13、14月是冬季。
设计一个机器人帮农场主来完成这份工作。
设计思路
设计一个抽象类,定义干活这个接口。由这个类派生4个子类,分别是春季、夏季、秋季和冬季。
定义一个农场机器人,这个机器人自动根据季节干活。这个机器人会包含一个状态类的指针,和状态标识,根据状态标识,调用对应的状态,并完成对应的工作。
UML
代码
#include <iostream>
using namespace std;
enum seasons {Spr = 1, Sum, Aut, Win};
class FarmRobot;
class Season
{
public:
virtual void doWork(FarmRobot* robot) = 0;
};
class FarmRobot
{
public:
Season* m_stat = 0;
seasons m_season;
FarmRobot(Season* stat, seasons season):m_stat(stat),m_season(season){}
~FarmRobot() {delete m_stat;}
void setStat(Season* stat)
{
delete m_stat;
m_stat = stat;
}
void doWork()
{
if(m_stat) m_stat->doWork(this);
}
};
class Winter : public Season
{
public:
void doWork(FarmRobot* robot);
};
class Autumn : public Season
{
public:
void doWork(FarmRobot* robot)
{
cout<<"Autumn: I'm harvesting!\n";
robot->setStat(new Winter());
}
};
class Summer : public Season
{
public:
void doWork(FarmRobot* robot)
{
cout<<"Summer: I'm watering!\n";
robot->setStat(new Autumn());
}
};
class Spring : public Season
{
public:
void doWork(FarmRobot* robot)
{
cout<<"Spring: I'm sowing!\n";
robot->setStat(new Summer());
}
};
//将Winter的函数实现放在最后,是为避免循环引用,否则编译出错
void Winter::doWork(FarmRobot* robot)
{
cout<<"Winter: I'm resting!\n";
robot->setStat(new Spring());
}
int main()
{
FarmRobot* robot = new FarmRobot(new Spring, Spr);
for(int s = Spr; s <= Win; s++)
{
robot->doWork();
}
delete robot;
return 0;
}