Unity【话大】设计模式之状态模式
前言:笔者在最开始写程序的时候经常会遇到一种情况,例如更改一个字段、或者添加一种小功能,就要把原来写过的东西几乎废弃掉,或者更改大量以前写过的代码。又或者自己写的东西时间久了再去回顾,完全找不到到时为什么这么写的头绪,如果遇到了Bug更是无法快速定位在哪里小范围出现的问题。如果你也经常遇到这种问题,就说明你现阶段非常需要学习下设计模式了。
在网上经常说的设计模式有23种,也有一些更多的设计模式,无非也是从这些设计模式中变种而来。如果让笔者来形容什么是设计模式,我认为设计模式是:一种思想,一种模式,一种套路,一种解决问题的高效策略。
有说的不正确或者不准确的地方欢迎留言指正
有什么有趣的写作技巧或者想法欢迎大家给我留言,大家的帮助是我写下去最有效的动力
今天笔者跟大家介绍一个新的设计模式----状态模式,下面以有A、B、C三个状态进行分别跳转,跳转顺序A--->B--->C,且这3个状态会有自己行为方式,就以这个示例展示状态模式如何使用
状态模式(State) 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
初始代码
public class Context
{
public string state;
public void Change()
{
if (state =="A")
{
this.Log("执行A先关操作");
}
else if (state =="B")
{
this.Log("执行B先关操作");
}
else if (state == "C")
{
this.Log("执行C先关操作");
}
}
}
调用
void Start()
{
Context context = new Context();
context.state = "A";
context.Change();
context.state = "B";
context.Change();
context.state = "C";
context.Change();
}
对应打印日志
老套路,我们开始进行抽象 封装和转移
首先我们把其中的if else判断中的行为进行封装,转移到不同的state中自行管理
public abstract class State
{
public abstract void Handle();
}
public class StateA : State
{
public override void Handle()
{
this.Log("执行A先关操作1");
this.Log("执行A先关操作2");
this.Log("执行A先关操作3");
}
}
public class StateB : State
{
public override void Handle()
{
this.Log("执行B先关操作1");
this.Log("执行B先关操作2");
this.Log("执行B先关操作3");
}
}
public class StateC : State
{
public override void Handle()
{
this.Log("执行C先关操作1");
this.Log("执行C先关操作2");
this.Log("执行C先关操作3");
}
}
对应Context中的更改
public class Context
{
public State state;
public void SetState(State state)
{
this.state = state;
}
public void Change()
{
if (state is StateA)
{
state.Handle();
}
else if (state is StateB)
{
state.Handle();
}
else if (state is StateC)
{
state.Handle();
}
}
}
调用就变成了这个样子
void Start()
{
Context context = new Context();
context.state = new StateA();
context.Change();
context.state = new StateB();
context.Change();
context.state = new StateC();
context.Change();
}
因为是他是按顺序的跳转机制,我们再次改造 ,把相关的跳转封装到各自的state中去
State
public abstract class State
{
public abstract void Handle();
public abstract void Change(Context context);
}
public class StateA : State
{
public override void Handle()
{
this.Log("执行-- A --先关操作1");
}
public override void Change(Context context)
{
Handle();
context.state = new StateB();
}
}
public class StateB : State
{
public override void Handle()
{
this.Log("执行-- B --先关操作1");
}
public override void Change(Context context)
{
Handle();
context.state = new StateC();
}
}
public class StateC : State
{
public override void Handle()
{
this.Log("执行-- C --先关操作1");
}
public override void Change(Context context)
{
Handle();
context.state = new StateA();
}
}
Contenxt
public class Context
{
public State state;
public Context(State state)
{
this.state = state;
}
public void Change()
{
state.Change(this);
}
}
调用
void Start()
{
Context context = new Context(new StateA());
context.Change(); //执行A并跳转B状态
context.Change(); //执行B并跳转C状态
context.Change(); //执行C并跳转A状态
context.Change(); //执行A并跳转B状态
context.Change(); //执行B并跳转C状态
context.Change(); //执行C并跳转A状态
}
以上就是状态模式的最终版。状态模式主要解决的是当控制一个对象状态装换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
所以当一个对象的行为取决于它的状态,并且他必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。
状态模式好处与用处
状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来
将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的装填和转换。
状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖
优点:
1、封装了转换规则,也就是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来
2、枚举可能的状态,在枚举状态之前需要确定状态种类。
3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态只需要改变对象状态即可改变对象的行为。
4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。