在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。在状态模式中,通过创建不同的状态对象和一个随着状态变化的context对象。
意图
允许对象在内部状态发生改变时,改变它的行为,对象看起来好像修改了它的类。
解决问题
对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
如何解决
将各种具体的状态类抽象出来
优点
1. 封装了转换规则
2. 枚举可能的状态,在枚举状态之前需要确定确定状态种类
3. 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为
4.允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块
5. 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数
缺点
1. 状态模式的使用必然会增加系统类和对象的个数
2. 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
3. 添加新的状态需要修改那些负责转换的源代码,否则无法转换到新增的状态,而且修改某个状态的行为也要修改源代码
使用场景
1. 行为随状态改变而改变的场景
2. 条件、分支语句的代替者
注意事项
在行为受约束的时候使用状态模式,而且状态不超过5个
UML类图
C++实现
例子:实现A 和 B状态转换
这里利用状态模式来实现,具体状态就是状态A与状态B,然后上下文存在一个“转换状态”的方法。之后状态A与状态B共同接口就是抽象状态State。
code:
//状态模式
class Context; //类,上下文,的提前引用,主要是用于通过C++的编译,需要提前声明这个类
class State //抽象状态
{
public:
virtual void switch_state() = 0;
};
//每一个具体状态,都必须有私有变量上下文Context *context;
//每一个具体状态的构造方法,都必须用this->context=context;实现将自己注册到上下文中。
//不得在每一个具体状态中实现转换状态的方法switch_state(),只能在类外实现,因为C++禁止类的互相调用,
//否则会出现error C2027: 使用了未定义类型的错误
class StateA : public State //具体状态
{
public :
StateA(Context * _context)
:context(_context)
{}
void switch_state();
private:
Context *context;
};
class StateB :public State
{
public :
StateB(Context * _context)
:context(_context)
{}
void switch_state();
private:
Context * context;
};
class Context
{
State *stateA, *stateB, *state;
public :
Context()
:stateA(new StateA(this))
, stateB(new StateB(this))
, state(stateA)
{}
void switch_state()
{
state->switch_state();
}
void SetState(State* _state)
{
state = _state;
}
State* getStateA()
{
return stateA;
}
State* getStateB()
{
return stateB;
}
};
//实现具体状态中,对应的转换方法
void StateA::switch_state()
{
context->SetState(context->getStateB());
cout << "已转换到状态B " << endl;
}
void StateB::switch_state()
{
context->SetState(context->getStateA());
cout << "已转换到状态A" << endl;
}
int test_State() //状态模式
{
Context* context = new Context();
context->switch_state();
context->switch_state();
context->switch_state();
context->switch_state();
delete context;
context = NULL;
system("pause");
return 0;
}