状态模式
就是让一个对象的行为随着内部状态的改变而变化,而该对象也像是换了类一样。
用游戏的方式来解释
就像是魔兽世界里的德鲁伊,有两种形态,人形状态和兽形状态,任意切换一种状态,他的技能也会变化,或者像英雄联盟里边的豹女,就是这种形态,玩家此时感觉就像操作一个不同的角色,程序里边感觉像是换了类一样。
这种形态切换的能力,是德鲁伊的一种“内部状态的转换”,转换完成后,是德鲁伊这个角色的另外一种行为模式,不过,还是德鲁伊他本身,这种模式就是状态模式。
状态模式的优点
减少错误的发生并降低维护难度:不再使用switch(m_state)来判断当前的状态,这样可以减少新增游戏状态时,因未能检查到所有switch(m_state)程序代码而造成的错误。
状态执行环境单一化:每个状态相关的都在一个状态类中,对于程序猿来说,可以清楚地了解每个状态执行时所需要配合的对象和类
项目之间可以共享场景:这种做法对网络游戏特别有用,玩家的上线、登录、验证、数据等同步过程,实现上有一定的复杂度。把这些复杂的操作放在共享的场景中,这样使用和维护就能节省很多开发时间和成本。
状态模式的缺点
当有大量状态时,使用状态模式就会产生过多状态类的情况,造成类爆炸的问题,但是跟传统switch(state_code)的实现方式相比,状态模式更利于项目后期的维护,因为状态模式可以清楚地了解每个场景状态所需要配合的类对象,减少因为新增状态而需要大量修改现有程序代码的维护成本。
下边是例子
namespace Leon_State
{
//状态持有者(持有目前的状态,并将有关的讯息传给状态)
public class Context
{
State m_State = null;
public void Request(int Value)
{
m_State.Handle(Value);
}
public void SetState(State theState)
{
Debug.Log("Context.SetState:" + theState);
m_State = theState;
}
}
//状态接口类(负责封装当Context处于特定状态时所该展现的行为)
public abstract class State
{
protected Context m_Context = null;
public State(Context theContext)
{
m_Context = theContext;
}
public abstract void Handle(int Value);
}
//状态A
public class ConcreteStateA : State
{
public ConcreteStateA(Context theContext) : base(theContext)
{ }
public override void Handle(int Value)
{
Debug.Log("ConcreteStateA.Handel");
if (Value > 10)
m_Context.SetState(new ConcreteStateB(m_Context));
}
}
//状态B
public class ConcreteStateB : State
{
public ConcreteStateB(Context theContext) : base(theContext)
{ }
public override void Handle(int Value)
{
Debug.Log("ConcreteStateB.Handel");
if (Value > 20)
m_Context.SetState(new ConcreteStateC(m_Context));
}
}
//状态C
public class ConcreteStateC : State
{
public ConcreteStateC(Context theContext) : base(theContext)
{ }
public override void Handle(int Value)
{
Debug.Log("ConcreteStateC.Handel");
if (Value > 30)
m_Context.SetState(new ConcreteStateA(m_Context));
}
}
}
测试
public class Leon_StateTest : MonoBehaviour
{
// Use this for initialization
void Start()
{
UnitTest();
}
private void UnitTest()
{
Context theContext = new Context();
theContext.SetState(new ConcreteStateA(theContext));
theContext.Request(5);
theContext.Request(15);
theContext.Request(25);
theContext.Request(35);
}
}
打印