当前位置:主页 > 查看内容

给女朋友讲设计模式 之 状态模式

发布时间:2021-07-14 00:00| 位朋友查看

简介:状态模式 当我在电脑前做我的独立游戏的时候,忽然嗅到让人放松的香味,又温柔又甜,不用想,她又想偷偷的在后面捂住我的眼睛,然后傻傻的问我她是谁.果不其然,她捂住了我的眼睛,然后在我的耳边说:猜猜我是谁呀我笑了笑,哈哈,你是谁呀她也不回答,从我的手臂下钻过……

状态模式

当我在电脑前做我的独立游戏的时候,忽然嗅到让人放松的香味,又温柔又甜,不用想,她又想偷偷的在后面捂住我的眼睛,然后傻傻的问我她是谁. 果不其然,她捂住了我的眼睛,然后在我的耳边说:"猜猜我是谁呀" 我笑了笑,"哈哈,你是谁呀" 她也不回答,从我的手臂下钻过来,坐在我的腿上.开始自顾自的玩弄自己的头发.

一会儿她转头问我:"你在写什么呢?"

我说:"我在写一个状态机."

她又问:"什么是状态机呀?"

我说:"状态机也就是切换状态的机器,属于状态模式,在游戏开发中十分常见,"状态"在游戏中许多环节都有,比如游戏中的AI,它就会有攻击状态,巡逻状态,等等."

她又问:"那是怎么从攻击到巡逻呢?" 我回答:"通过外部环境的影响然后自身内部完成状态的切换.举个例子:假如我现在设计一个游戏,游戏的主人公有个特殊的属性,就是每当月圆之夜,他一遇到月光,他就会变成一个狼人,他的攻击模式就会变成"利爪攻击","超远弹跳","血量加厚"等技能或属性 ,但是如果月光消息就会变回自身的人类状态.那他的攻击就有"利剑攻击","手枪攻击","长矛攻击",血量也比较少,那么这个时候这种就基本是一个状态模式了."

"哦.",她似乎听懂了,她继续说:"就是外部环境影响,然后切换成被影响的状态,对吧."

"对,这个切换一般是在内部切换,换句话说就是这个人变成狼人是从他内部变化的,他受到了月光的影响,自己从内部从人变成了狼人."

"那你一般怎么写呀?"她问.

"在代码中写的话就是首先要有一个"外部环境"的一个类,这个类就是用来影响这个状态的,我们可以这么写:

public class Context   
{

}

"

"这样写就是一个类了嘛?"

"对,类的关键字"class,接着还要再写一个抽象类 State"

public abstract class State
{

}

"

"什么叫抽象类啊?"她迫不及待的问我.

我说抽象类就是专门给子类继承用的,抽象类里面必须要有抽象方法,而且里面只能有抽象方法,这个抽象方法只有签名没有方法体.

"啊?什么是签名,什么是方法体呀?"

我看了看她,眼睛里都是迷惑,此时她的表情真的很美,真的很想亲一口,但是我必须要把这些给她讲明白,我咽了一口口水,继续和她说道:"方法的签名就是方法的名字,方法体就是这个函数的实体,换句话说就是{}里面的东西,叫方法体,那么这个抽象方法就是

public abstract class State
{
    public abstract void Handle(int value);
}

"

"这样的就是子类必须实现这个Handle的虚方法是吗?"

"是的"我接着说但是,光有状态的行为还不行,这个行为就是Handle方法,状态也需要知道"环境"的具体情况,才好根据环境来切换状态".

"啊,为什么不是自动的呢?当环境变化的时候,State自动的知道啊"

我说,因为在计算机世界中还是和我们现实世界中有区别的,因为计算机是没有"眼睛"的,我们可以看到,但是在计算机的世界中,我们是没有办法看到某个状态的改变的,只有通过拿到某个类或者方法的引用,才能知道这个类或者方法的状态.

"啊,那,引用又是什么啊?"

她有些气馁甚至想跳下去,我双臂收小一点,防止她真的跑了.我继续说道:"引用就相当于这个类或者这个方法的分身,这个分身和原先的本体是一样的,引用能感知到本体的一切变化,可以理解成代言人"

"哦哦"

"嗯,那么我们再将环境和状态类补全"

public class Context   {

    State m_state = null;
    public void SetState(State state)
    {
        Debug.Log("Context.Setstate :" + state);
        m_state = state;
    }

    public void Request(int value)
    {
        m_state.Handle(value);
    }
}
public abstract class State
{
    protected Context context = null;
    public State(Context context)
    {
        this.context = context;
    }
    public abstract void Handle(int value);
}

然后我们再写状态的具体实现:

//具体状态A
public class ConcreteStateA : State
{
    public ConcreteStateA(Context context) : base(context)
    {

    }
    public override void Handle(int value)
    {
        Debug.Log("ConcreteStateA .Handle");
        if (value == )
        {
            context.SetState(new ConcreteStateB(context));
        }
    }
}

//具体状态B
public class ConcreteStateB : State
{
    public ConcreteStateB(Context context) : base(context)
    {

    }
    public override void Handle(int value)
    {
        Debug.Log("ConcreteStateB .Handle");
        if (value == )
        {
            context.SetState(new ConcreteStateC(context));
        }
    }
}

//具体状态C
public class ConcreteStateC : State
{
    public ConcreteStateC(Context context) : base(context)
    {

    }
    public override void Handle(int value)
    {
        Debug.Log("ConcreteStateC .Handle");
        if (value == )
        {
            context.SetState(new ConcreteStateA(context));
        }
    }

"那个base是干嘛的呀"

我一猜她就会问这个,我说:"这个base就是代表父类.括号里面的值就是代表这个子类用的就是就是父类中的值.简单点来说就是在派生类中调用基类构造函数."

3个子类实现了state父类中的抽象方法.

那么这个时候他的Handle,里面也实现了状态转换的功能.如果我们在unity中来测试一下的话我们只需新建一个脚本实例一下context然后再通过context中的setstate方法设置状态就可以了.

    void Start () {
        Context context = new Context();
        context.SetState(new ConcreteStateA(context));
        context.Request();
        context.Request();
        context.Request();
    }

你看,运行之后就是这样的.

她看了看,说:"emmm,一点儿也不好玩".

说着就跳了下去,顺便问了问我今天想吃什么.我看着她笑着说:"你煮什么我吃什么".

…END…


本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文

  • 周排行
  • 月排行
  • 总排行

随机推荐