设计模式 之 状态模式用游戏中的例子解释设计模式

xiaoxiao2021-02-28  70

此类型的博客的写作初衷在于,整理自己平时所学的知识,随时欢迎各路大神指正

//绿色字的内容为注释

什么时候使用状态模式/状态模式有什么用?

    官方的说法是,当对象有很明确的状态划分的时候;

        1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。

       2.一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。360百科

       如:地下城与勇士中,战斗法师的觉醒技能:变身贝亚娜斗神;如下情况通常会使用状态模式            当玩家变身为贝亚娜状态之前,战斗法师的前冲攻击(→→+X)是这样的——
战斗法师使用手中的武器敲击敌方的头部;             当玩家变身为贝亚娜状态之后,变身的战斗法师的前冲攻击(→→+X)是这样的—— 战斗法师使用手中矛形的武器突刺对方

    总结来讲就是://这种方法只是此模式的一种用法

        当你希望用户(玩家

        使用相同的操作方式/*都是释放前冲攻击*/调用相同的函数名,但实际会因当前的状态不同,使用的是不同的函数,或者说函数调用的方式不变),

        游戏或者程序会产生不同的操作响应时就可以使用状态模式;

    状态模式的好处

        符合单一指责原则开闭原则迪米特法则最少知道法则
         将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。

状态模式的核心写法/如何写一个状态模式?小部分内容参考自《设计模式与游戏完美开发》

               想写一个状态模式的基本框架很简单,我们只需要写三部分(三种类型的类)的内容

                    1、Context状态的拥有者:战斗法师

                    2、IState抽象状态类/抽象状态模板,定义了前冲攻击这个技能,但并不会写出具体的实现方法/*通常是虚方法*/,通常会使用abstract抽象类去写,也可以使用接口Instance,或者普通类class

                    3、继承IState的具体状态类通常有多个 这个类override重写了前冲攻击这个技能的技能效果

                        1)State战斗法师战斗法师使用手中的武器敲击敌方的头部;

                       (2)State贝亚娜斗神(战斗法师使用手中矛形的武器突刺对方;

               这三部分拆分开来讲:

                  Context状态的拥有者只需要写3条内容:

                    1、存放IState类的字段//用来存放当前状态,和下面类似

                    2、SetState(IState)方法//用来设置当前状态,和下面类似/给上面的一条赋值

                    3、Requast()//可以同时写多个这种类型的方法,方法内部,放入对应的状态框架中的方法,像什么Update()方法,Enable()方法等专门给外界调用的方法,是子状态中的方法与外界交流的唯一出口

        public class Context { /// <summary> /// 用来保存当前状态 /// </summary> protected State state; /// <summary> /// 给外界调用的设置状态方法 /// </summary> /// <param name="state"></param> public void SetState(State state) { this.state = state; } /// <summary> /// 使用状态模式的方法,通过这个可以间接的转换状态 /// </summary> /// <param name="var"></param> public void Request(int var) { state.Headle(var); } }

                 IState状态的框架也同样有3样东西:

                    1、存放Context类的字段//用来方便子状态使用,和上面类似:如 切换状态

                    2、自身的构造函数//用来给Context赋值,和上面类似/给上面一条赋值

                    3、留给子状态继承并重写的所有抽象方法//和上面一样,也不限于一个方法

        public abstract class State { /// <summary> /// 状态中保存有当前状态的拥有者 /// </summary> protected Context context; /// <summary> /// 想创建一个State 必须new一个此状态的拥有者,没有拥有者哪来的状态 /// </summary> /// <param name="context"></param> public State(Context context) { this.context = context; } /// <summary> /// 给其他扩展状态设置的此状态执行的操作 /// </summary> /// <param name="var"></param> public abstract void Headle(int var); }

                子状态只有2个主要任务:

                    1、重写父类方法,实现功能

                    2、切换状态

                    //使用默认构造函数

        public class ConcreteStateA : State { public ConcreteStateA(Context context) : base(context) { } public override void Headle(int var) { if (var > 10) context.SetState(new ConcreteStateB(context)); Debug.Log("ConcreteStateA"); } } public class ConcreteStateB : State { public ConcreteStateB(Context context) : base(context) { } public override void Headle(int var) { if (var > 40) { context.SetState(new ConcreteStateA(context)); } Debug.Log("ConcreteStateB"); } }

写好了状态模式后,又该如何去使用状态模式呢?

            使用状态模式分3

                        1、new一个状态的拥有者出来//连角色都没有,怎么可能让角色有状态

                        2、给刚刚new出来的拥有者SetState()设置一个初始状态//创建好了新角色以后,此角色总得有个状态吧,让她站着还是坐着随你便

                        3、使用拥有者中的公有方法来间接调用子状态中的方法

public class StateText : MonoBehaviour { void Start() { UnitTest(); } void UnitTest() { Context theContext = new Context();//new一个状态的拥有者 theContext.SetState(new ConcreteStateA(theContext));//设置一个初始状态,这里传入new出的拥有者的目地是,给IState中的Context赋值 theContext.Request(5);//使用拥有者中的公有方法来间接调用子状态中的方法 theContext.Request(15); theContext.Request(25); theContext.Request(35); theContext.Request(55); } }
转载请注明原文地址: https://www.6miu.com/read-2632087.html

最新回复(0)