状态模式
(1)在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
(2)状态模式UML图:
(3)在状态模式结构图中包含如下几个角色:
● Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
● State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
● ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
(4)在状态模式的使用过程中,一个对象的状态之间还可以进行相互转换,通常有两种实现状态转换的方式:
1. 统一由环境类来负责状态之间的转换,此时,环境类还充当了状态管理器(State Manager)角色,在环境类的业务方法中通过对某些属性值的判断实现状态转换。
2. 由具体状态类来负责状态之间的转换,可以在具体状态类的业务方法中判断环境类的某些属性值再根据情况为环境类设置新的状态对象,实现状态转换
(5)完整可运行的代码
电灯拥有开和关两种状态,我们只需要点击电灯的开关即可实现打开和关闭不停的切换,下面的实例中状态的切换是在具体的状态中。
light.hxx文件:定义了电灯类
#include"state.hxx"
class XState;
class Light
{
public:
Light(XState* state) { maState = state; }
void setState(XState * state) { maState = state; }
void request();
private:
XState* maState;
};
light.cpp文件:电灯类的具体实现
#include"light.hxx"
void Light::request()
{
maState->handle(this);
}
实现了关键接口request(),调用具体状态的处理函数。
state.hxx文件:定义了状态类
#include"light.hxx"
class Light;
class XState
{
public:
virtual void handle(Light* light) = 0;
};
//开灯状态
class onState : public XState
{
public:
void handle(Light* light) override;
};
//关灯状态
class offState :public XState
{
public:
void handle(Light* light) override;
};
state.cxx文件:状态类的实现
#include<iostream>
#include"state.hxx"
using namespace std;
//当是开灯状态下,点击电灯电源按钮,电灯切换到关灯状态,关闭电灯。
void onState::handle(Light* light)
{
cout << "turn off the light"<< endl;
light->setState(new offState);
}
//当是关灯状态下,点击电灯电源按钮,电灯切换到开灯状态,打开电灯。
void offState::handle(Light* light)
{
cout << "turn on the ligth"<< endl;
light->setState(new onState);
}
可以看到在状态类中进行了状态切换,就是上面提到的第二种转换方案。
main.cxx文件:
#include<iostream>
#include"light.hxx"
#include"state.hxx"
int main()
{ //初始为关灯状态。
XState* offstate = new offState();
Light* light = new Light(offstate);
light->request();
light->request();
system("pause");
return 0;
}
light不停的调用request(),状态在不停的切换,电灯在不停的打开和关闭。一个对象(电灯)在其内部状态改变时改变它的行为(开/关灯),对象看起来似乎修改了它的类,这就是状态模式。
(6)运行截图:
(7)状态模式和策略模式的区别:
看UML图,他们两基本一模一样。
状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现,当发现传入参数不是自己这个状态所对应的参数,则自己给Context类切换状态;