状态模式
定义:
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。状态模式是一种对象行为型模式。
在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理。最直接的解决方案是将这些所有可能发生的情况全都考虑到。然后使用if... ellse语句来做状态判断来进行不同情况的处理。但是对复杂状态的判断就显得“力不从心了”。随着增加新的状态或者修改一个状体(if else(或switch case)语句的增多或者修改)可能会引起很大的修改,而程序的可读性,扩展性也会变得很弱。维护也会很麻烦。那么我就考虑只修改自身状态的模式。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的逻辑判断简化。
优点:
1 ) 它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来: State模式将所有与一个特定的状态相关的行为都放入一个对象中。因为所有与状态相关的代码都存在于某一个State子类中, 所以通过定义新的子类可以很容易的增加新的状态和转换。另一个方法是使用数据值定义内部状态并且让 Context操作来显式地检查这些数据。但这样将会使整个Context的实现中遍布看起来很相似的条件if else语句或switch case语句。增加一个新的状态可能需要改变若干个操作, 这就使得维护变得复杂了。State模式避免了这个问题, 但可能会引入另一个问题, 因为该模式将不同状态的行为分布在多个State子类中。这就增加了子类的数目,相对于单个类的实现来说不够紧凑。但是如果有许多状态时这样的分布实际上更好一些, 否则需要使用巨大的条件语句。正如很长的过程一样,巨大的条件语句是不受欢迎的。它们形成一大整块并且使得代码不够清晰,这又使得它们难以修改和扩展。 State模式提供了一个更好的方法来组织与特定状态相关的代码。决定状态转移的逻辑不在单块的 i f或s w i t c h语句中, 而是分布在State子类之间。将每一个状态转换和动作封装到一个类中,就把着眼点从执行状态提高到整个对象的状态。这将使代码结构化并使其意图更加清晰。
2) 它使得状态转换显式化: 当一个对象仅以内部数据值来定义当前状态时 , 其状态仅表现为对一些变量的赋值,这不够明确。为不同的状态引入独立的对象使得转换变得更加明确。而且, State对象可保证Context不会发生内部状态不一致的情况,因为从 Context的角度看,状态转换是原子的—只需重新绑定一个变量(即Context的State对象变量),而无需为多个变量赋值
3) State对象可被共享 如果State对象没有实例变量—即它们表示的状态完全以它们的类型来编码—那么各Context对象可以共享一个State对象。当状态以这种方式被共享时, 它们必然是没有内部状态, 只有行为的轻量级对象。
缺点:
1) 状态模式的使用必然会增加系统类和对象的个数。
2) 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
应用场景:
在下面的两种情况下均可使用State模式:if else(或switch case)语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常 , 有多个操作包含这一相同的条件结构。 State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
(1)对象的行为依赖于它的状态,并且可以在运行时根据状态改变行为。
(2)代码中包含大量与对象状态有关的if/else语句,这些条件对应于对象的各种状态,这些冗余条件语句的出现导致代码的可维护性和灵活性变差,这种情况适合使用状态模式进行优化。
UML图:
环境类(Context): 定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
抽象状态类(State): 定义一个接口以封装与Context的一个特定状态相关的行为。
具体状态类(ConcreteState): 每一子类实现一个与Context的一个状态相关的行为。
class Context;
class State//抽象状态类
{
public:
virtual void Handle(Context* pContext)=0;
~State();
protected:
State();
private:
};
class ConcreteStateA : public State
{
public:
ConcreteStateA(){}
~ConcreteStateA(){}
virtual void Handle(Context* pContext)
{
cout << "ConcreteStateA" << endl;
pContext->ChangeState(new ConcreteStateB());
}
};
class ConcreteStateB : public State
{
public:
ConcreteStateB(){}
~ConcreteStateB(){}
virtual void Handle(Context* pContext)
{
cout << "ConcreteStateB" << endl;
pContext->ChangeState(new ConcreteStateC());
}
};
class ConcreteStateC : public State
{
public:
ConcreteStateC(){}
~ConcreteStateC(){}
virtual void Handle(Context* pContext)
{
cout << "ConcreteStateC" << endl;
pContext->ChangeState(new ConcreteStateA());
}
};
class Context
{
private:
State *_state;
public:
Context(State* pState):_state(pState){}
~Context(){}
void Request()
{
if(_state)
{
_state->Handle(this);
}
}
void ChangeState(State* pState)
{
_state=pState;
}
};
int main()
{
State* pState = new ConcreteStateA();
Context* pContext = new Context(pState);
pContext->Request();
pContext->Request();
pContext->Request();
pContext->Request();
pContext->Request();
return 0;
}
例子:点击打开链接
一般汽车发动机工作时有四种状态,吸气、压缩、做功和排气。
在运行时,不同的状态会有不同的行为,当前的状态机在适当的时候会过渡到下一状态。
其实用户在使用时根本不知道当前的状态,也无需知道当前的状态。用户只需要给发动机一个初始状态,最后得到一个停止状态就行了。
结构图如下:#include <string>
#include <iostream>
using namespace std;
class Work;
//抽象状态类
class State
{
public:
virtual void Operation(Work *work) {}
};
//工作
class Work
{
private:
State *m_state; //目前状态
int m_step; //步骤
public:
Work(State *state): m_state(state), m_step(0){}
~Work()
{
delete m_state;
}
int GetStep()
{
return m_step;
}
void SetStep(int step)
{
m_step = step;
}
void SetState(State *state)
{
delete m_state;
m_state = state;
}
void Operation()
{
m_state->Operation(this);
}
};
//排气状态
class ExhaustState: public State
{
public:
void Operation(Work *work) //排气操作
{
if(work->GetStep() == 4)
{
cout<<"Step : "<<work->GetStep()<<"排气操作"<<endl;
}
}
};
//做功状态
class ActState: public State
{
public:
void Operation(Work *work) //做功操作
{
if(work->GetStep() == 3)
{
cout<<"Step : "<<work->GetStep()<<"做功操作"<<endl;
}
else
{
work->SetState(new ExhaustState());
work->Operation();
}
}
};
//压缩状态
class CompressState: public State
{
public:
void Operation(Work *work) //压缩操作
{
if(work->GetStep() == 2)
{
cout<<"Step : "<<work->GetStep()<<"压缩操作"<<endl;
}
else
{
work->SetState(new ActState());
work->Operation();
}
}
};
//吸气状态
class InhaleState: public State
{
public:
void Operation(Work *work) //吸气操作
{
if(work->GetStep() == 1)
{
cout<<"Step : "<<work->GetStep()<<"吸气操作"<<endl;
}
else
{
State *p = new CompressState();
work->SetState(p);
work->Operation();
}
}
};
//测试代码
int main()
{
State* st = new InhaleState(); //初始状态
Work *work = new Work(st);
for(int i = 1; i < 5; ++i)
{
work->SetStep(i);
work->Operation(); //操作
}
delete work;
return 0;
}