把状态模式用于游戏角色状态

这是重构之前的示例代码:

    class Role
    {
        [Flags]
        //标志枚举
        public enum StateEnum
        {

            State1 = 0,
            State2 = 2,
            State3 = 4,
            State4 = 8,
            //一些状态
        }
        private StateEnum state = StateEnum.State1;

        public StateEnum State
        {
            set { state = value; }
            get { return state; }
        }

        private bool f1 = false;
        private bool f2 = true;

        public void Update()
        {
            if (!f1)
            {
                bool f3 = false;
                //代码段6
                switch (State)
                {
                    case StateEnum.State1:
                        //代码段1
                        break;
                    case StateEnum.State2:
                        //代码段2
                        if (f3) {
                            //代码段8
                        }
                        break;
                    case StateEnum.State3:
                        //代码段3
                        break;
                    case StateEnum.State4:
                        //代码段4
                        break;
                    default:
                        //代码段5
                        break;
                }
            }
            if (f2) {
                //代码段7
            }
        }
    }

其中,那些布尔型变量都是演示用的,注释写的代码段也是演示用的。

这段代码很可能出现了Large Class(过大的类)和Long Method(过长函数)坏味道,所以我们就可以用重构方法进行重构。

我们看,这个根据角色状态改变角色参数的switch结构在这个Update方法里,但是非常之乱套。我们先用Extract Method(提炼函数)重构手法进行重构,得到如下的结果:

    class Role
    {
        [Flags]
        //标志枚举
        public enum StateEnum
        {

            State1 = 0,
            State2 = 2,
            State3 = 4,
            State4 = 8,
            //一些状态
        }
        private StateEnum state = StateEnum.State1;

        public StateEnum State
        {
            set { state = value; }
            get { return state; }
        }

        private bool f1 = false;
        private bool f2 = true;

        public void Update()
        {
            if (!f1)
            {
                bool f3 = false;
                //代码段6
                Switch(f3);
                //位置1
            }
            if (f2) {
                //代码段7
            }
        }
        private void Switch(bool f3) {
            switch (State)
            {
                case StateEnum.State1:
                    //代码段1
                    break;
                case StateEnum.State2:
                    //代码段2
                    if (f3)
                    {
                        //代码段8
                    }
                    break;
                case StateEnum.State3:
                    //代码段3
                    break;
                case StateEnum.State4:
                    //代码段4
                    break;
                default:
                    //代码段5
                    break;
            }
            //位置2
        }
    }

看到这个例子,原先的局部变量变成了提炼出来的函数的参数,在原地方调用这个新函数。

然后,我们使用Replace Conditional with Polymorphism(以多态取代条件表达式)重构手法和状态模式,把除了6和7以外的其他代码段都放进新的类里边。

先写一个新接口:

    interface IState
    {
        void StateUpdate();
    }

然后新建一个实现此接口的类:

    class State1:IState
    {
        public void StateUpdate() {
            //代码段1
        }
    }

在原先的Role类中新建一个IState类型字段iState,把case StateEnum.State1:中的代码改为iState = new State1();iState.StateUpdate();,这时再把iState.StateUpdate();移出switch结构,放到Switch(bool)方法最下边,也就是位置2,或者位置1也行。而对于case StateEnum.State2:这样的情况,可以给State2的构造方法增加一个参数,就可以了。

这时发现new状态的操作太多了,可以给这些状态类来个单例,单例模式很简单的,这里就不说了。至于State2,就要特殊情况特殊处理,可以在单例静态方法里根据一个静态字段进行判断,这个静态字段就是这个类里保存的f3,保存了上次产生的实例的参数,或者根据实际情况,也可以来个哈希表记录这个参数和对象实例的对应关系。或者也可以把IState接口换成一个抽象类,然后在其中写一个静态工厂函数,这个工厂函数的参数就是游戏角色的状态类型,这就用到了Replace Constructor with Factory Method(以工厂函数取代构造函数),这时State2的f3参数也可以放在这个抽象的基类里边,这些都看情况而定。

有关重构的内容,大家可以Google搜索,或者参考《重构:改善既有代码的设计》这本书。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jether

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值