Replace Type Code with Class (以类取代类型码)

Summary 类之中有一个数值类型码,但它并不影响类的行为。以一个新的类替换该数值类型码。java

                                               

动机:函数

  在以C为基础的变成语言中,类型码或枚举值很常见。若是带着一个有意义的符号名,类型码的可读性仍是不错的。问题在于,符号名终究是个别名,编译器所看见的、进行类型校验的,仍是背后那个数值。任何接受类型码做为参数的函数所指望的其实是一个数值,没法强制使用符号名。这会大大下降代码的可读性,从而成为bug之源。测试

若是把那样的数值换成一个类,编译器就能够对这个类进行类型校验。只要为这个类提供工厂函数,你就额能够始终保证只有合法的实例才会被建立出来,并且它们都会被传递给正确的宿主对象。spa

可是在使用Replace Type Code with Class以前,你应该先考虑类型码的其余替换方式。只有当类型码是纯数据时(也就是类型码不会在switch语句中引发行为变化时),你才能以类来取代它。Java只能以整数做为switch语句的判断依据,不能使用任意类,所以在那种状况下不可以以类替换类型码。更重要的是:任何switch语句都应该运用Replace Conditional with Polymorphism去掉。为了进行那样的重构,你首先运用Replace Type Code with SubclassesReplace Type Code with State/Strategy,把类型码处理掉。code

即便一个类型码不会因其数值的不一样而引发行为上的差别,宿主类中的某些行为仍是有可能更适合置放于类型码中,所以你还应该留意是否有必要使用Move Method将一两个函数搬过去。对象

作法:接口

1.为类型码创建一个类get

à这个类须要一个用以记录类型码的字段,其类型应该和类型码相同,并应该由对应的取值函数,此外还应该用一组静态变量保存容许被建立的实例,并以一个静态函数根据本来的类型码返回合适的实例。编译器

2.修改源类实现,让它使用上述新建的类。it

à维持原先以类型码为基础的函数接口,但改变静态字段,以新建的类产生代码。而后修改类型码相关函数,让它们也重新建的类中获取类型码。

3.编译,测试。

à此时,新建的类能够对类型码进行运行期检查。

4.对于源类中每个使用类型码的函数,相应创建一个函数,让新函数使用新建的类。

à你须要创建“以新类实例为自变量”的函数,用以替换原先“直接以类型码为参数”的函数。你还须要创建一个“返回新类实例”的函数,用以替换原先“直接返回类型码”的函数。创建新函数前,你可使用Rename Method修改原函数名称,明确指出哪些函数仍然使用旧式的类型码,这每每是个明智之举。

5.逐一修改源类用户,让它们使用新接口。

6.每修改一个用户,编译并测试。

à你也可能须要一次性修改多个彼此相关的函数,才能保持这些函数之间的一致性,才能顺利地编译、测试

7.删除使用类型码的旧接口,并删除保存旧类型码的静态变量。

8.编译,测试。

  范例:

  每一个人都拥有四种血型中的一种。咱们以Person来表示“人”,以其中的类型码表示“血型”:

class Person{
    public static final int O = 0;
    public static final int A = 1;
    public static final int B = 2;
    public static final int AB = 3;
    
    private int _bloodGroup;
    
    pulic Person(int bloodGroup){
        _bloodGroup = bloodGroup;
    }
    
    public void setBloodGroup(int arg){
        _bloodGroup = arg;
    }
    
    public int getBloodGroup(){
        return _bloodGroup;
    }
}

 首先,咱们创建一个新的BloodGroup类,用以表示“血型”,并在这个类实例中保存本来的类型码数值:

class BloodGroup{
    public static final BloodGroup O = new BloodGroup(0);
    public static final BloodGroup A = new BloodGroup(1);
    public static final BloodGroup B = new BloodGroup(2);
    public static final BloodGroup AB = new BloodGroup(3);
    
    public static final BloodGroup[] _values = {O, A, B, AB};
    
    private final int _code;
    
    private BloodGroup(int code){
        _code = code;
    }
    
    public int getCode(){
        return _code;
    }
    
    public static BloodGroup code(int arg){
        return _values[arg];
    }
}

而后,把Person中的类型码改成使用BloodGroup类:

class Person{
    public static final int O = BloodGroup.O.getCode();
    public static final int A = BloodGroup.A.getCode();
    public static final int B = BloodGroup.B.getCode();
    public static final int AB = BloodGroup.AB.getCode();
    
    private BloodGroup _bloodGroup;
    
    pulic Person(int bloodGroup){
        _bloodGroup = BloodGroup.code(bloodGroup);
    }
    
    public void setBloodGroup(int arg){
        _bloodGroup = BloodGroup.code(arg);
    }
    
    public int getBloodGroup(){
        return _bloodGroup.getCode();
    }
}

如今由于BloodGroup类而拥有了运行期检验能力。为了真正从这些改变中获利,咱们还必须修改Person的用户,让它们以BloodGroup对象表示类型码,而再也不使用整数。

首先,使用Rename Method修改类型码访问函数的名称,说明当前状况:

class Person...
    public int getBloodGroupCode(){
        return _bloodGroup.getCode();
    }

而后为Person加入一个新的取值函数,其中使用BloodGroup;

public BloodGroup getBloodGroup(){
    return _bloodGroup;
}

另外,还要创建新的构造函数和设值函数,让它们也使用BloodGroup;

public Person (BloodGroup bloodGroup){
    _bloodGroup = bloodGroup;
}

public void setBloodGroup(BloodGroup arg){
    _bloodGroup = arg;
}

如今,继续处理person用户。此时应该注意,每次只处理一个用户,这样才能够保持小步前进。每一个用户须要的修改方式可能不一样,这使得修改过程更加棘手。对Person内的静态变量的全部引用点也须要修改。所以,下列代码:

Person thePerson = new Person(Person.A);

就变成了

Person thePerson = new Person(BloodGroup.A);

原来调用取值函数的代码必须改成调用BloodGroup的取值函数。所以下列代码

thePerson.getBloodGroupCode();

变成了

thePerson.getBloodGroup.getCode();

设值函数也同样。所以下列代码

thePerson.setBloodGroup(Person.AB);

变成了

thePerson.setBloodGroup(BloodGroup.AB);

修改完毕Person的全部用户以后,就能够删掉本来使用整数类型的那些旧的取值函数、构造函数、静态变量和设值函数了。

还能够将BloodGroup中使用整数类型的函数声明为private,由于再也没有人会使用它们了:

class BloodGroup...
    private int getCode(){
        return _code;
    }
    private static BloodGroup code(int arg){
        return _values[arg];
    }
相关文章
相关标签/搜索