这是重构之前的示例代码:
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搜索,或者参考《重构:改善既有代码的设计》这本书。