在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
1.模式定义
状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。
2.模式结构
组合模式包含如下角色:
Context: 环境类
State: 抽象状态类
ConcreteState: 具体状态类
3.代码分析
State.h
class Context; //前置声明
class State
{
public:
State() {};
virtual ~State() {};
virtual void handle(Context *context) = 0;
};
Context.h
#pragma once
#include "State.h"
class Context
{
public:
Context();
virtual ~Context() {};
void changeState(State * st);
void request();
private:
State *m_pState;
};
Context.cpp
#include "Context.h"
#include "ConcreteStateA.h"
Context::Context()
{
m_pState = ConcreteStateA::Instance();
}
void Context::changeState(State * st) {
m_pState = st;
}
void Context::request() {
m_pState->handle(this);
}
ConcreteState.h
#pragma once
#include "State.h"
#include "Context.h"
class ConcreteStateA : public State
{
public:
virtual ~ConcreteStateA();
static State * Instance();
virtual void handle(Context * c);
private:
ConcreteStateA() {};
static State * m_pState;
};
ConcreteState.cpp
#include "ConcreteStateA.h"
#include "ConcreteStateB.h"
#include "Context.h"
#include <iostream>
using namespace std;
State * ConcreteStateA::m_pState = NULL;
ConcreteStateA::~ConcreteStateA()
{
delete m_pState;
}
State * ConcreteStateA::Instance()
{
if (NULL == m_pState)
{
m_pState = new ConcreteStateA();
}
return m_pState;
}
void ConcreteStateA::handle(Context * c)
{
cout << "Doing something in State A.\n Done,change state to B" << endl;
c->changeState(ConcreteStateB::Instance());
}
测试代码:
int main(int argc, char *argv[])
{
Context * c = new Context();
c->request();
c->request();
c->request();
delete c;
return 0;
}
4.模式优点
封装了转换规则。
枚举可能的状态,在枚举状态之前需要确定状态种类。
将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
5.模式缺点
状态模式的使用必然会增加系统类和对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。
6.总结
状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象,状态模式是一种对象行为型模式。
状态模式包含三个角色:环境类又称为上下文类,它是拥有状态的对象,在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象,可以定义初始状态;抽象状态类用于定义一个接口以封装与环境类的一个特定状态相关的行为;具体状态类是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
状态模式描述了对象状态的变化以及对象如何在每一种状态下表现出不同的行为。
状态模式的主要优点在于封装了转换规则,并枚举可能的状态,它将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为,还可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数;其缺点在于使用状态模式会增加系统类和对象的个数,且状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,对于可以切换状态的状态模式不满足“开闭原则”的要求。
状态模式适用情况包括:对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为;代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。