class 中有一个数值型别码,但它不影响class的行为

以一个新的class替换该数值型别码。

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;

==>

class Person ...
private BloodGroup _bloodGroup;

 

动机

有符号名是会增加可读性。

但是符号名只是个别名,编译器只认识和检查数字,而不是符号名。

任何方法的参数都是数字,而无法强制使用符号名。

这会降低可读性,并且会增加Bug。

如果你把数字转换成类的话,就可以进行检查。

并且,如果在类中提供正确的工厂方法的话,就可以保证只有正确的对象才会被创建。

在使用Replace Type Code with Class之前,你要保证没有switch方法去执行不同的行为。

因为在Java中,switch方法不能进行Class的判断,这样转换会失败。

更重要的是,所有的switch都应该使用Replace Conditional with Polymorphism进行重构。

为了执行这项重构,必须首先使用Replace Type Code with Subclasses 或者Replace Type Code with State/Strategy。

即使,不存在根据它的值而执行不同的行为,但是有些行为还是比较适合放在Type Code Class中,所以要判断是否要使用Move Method进行行为的搬移。

 

作法:

1. 为type code 建立一个Class

这个class中需要一个用以纪录type code的值域,其类型应该和type code相同。并应该有取值函数,

此外还应该用static变量保存一组可以被创建的实体,并以一个static函数根据 type code返回相应的实体。

2. 修改原来的class,让它使用上述新建的class.

维持原先以type code为基础的函数接口,但改变static值域,以新建的class产生代码。然后修改type code相关函数,让它们也从新建的class中获取代码。

3、编译,测试

此时新建的class可以对type code进行运行期检查

4、对于source class中每一个使用type code的函数,相应建立一个函数,让新函数使用新建的class

 你需要建立[以新class实体为自变量]的函数,用以替换原先直接以type code为引数的函数。

你还需要建立一个[返回新class实体的函数],用以替换原先直接返回type code的函数

建立新函数前,你可以使用Rename Method修改原函数名称,明确指出哪些函数仍然使用旧式的type code,这往往是个明智之举。

5、逐一修改source class用户,让它们使用新接口。

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

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

7、删除使用type code的旧接口,并删除保存旧type code的静态变量

8、编译、测试。

 

我们有一个用type code来表示血型的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;
public Person (int bloodGroup) {
_bloodGroup = bloodGroup;
}
public void setBloodGroup(int arg) {
_bloodGroup = arg;
}
public int getBloodGroup() {
return _bloodGroup;
}
}

 

我首先新建BloodGroup Class表示血型,并在这个Class中保存type code

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);
private 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中的type code改成新的Class中的code

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;
public Person (int bloodGroup) {
_bloodGroup = BloodGroup.code(bloodGroup);
}
public int getBloodGroup() {
return _bloodGroup.getCode();
}
public void setBloodGroup(int arg) {
_bloodGroup = BloodGroup.code (arg);
}
}

现在在BloodGroup Class中已经有了运行时的检查,但是为了在改变中获利,需要把Person中的数字改成BloodGroup。

首先,使用Rename Method修改type code访问函数的名称,说明当前情况:

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

然后,我增加一个新的get方法,返回BloodGroup

public BloodGroup getBloodGroup() {
return _bloodGroup;
}

另外,我还要建立新的使用BloodGroup的构造函数和设置函数

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

现在,我要继续处理Person用户。每次只处理一个用户,这样才可以保持小步前进。对Person内的所有static变量的所有引用点也需要修改,因此

Person thePerson = new Person(Person.A)

变成

Person thePerson = new Person(BloodGroup.A);

调用取值函数必须改为调用新取值函数。因此

thePerson.getBloodGroupCode()

变成

thePerson.getBloodGroup().getCode()

设置函数也一样。因此

thePerson.setBloodGroup(Person.AB)

变成

thePerson.setBloodGroup(BloodGroup.AB)

修改完毕所有的客户端后,我就可以删除那些原本使用整数的旧的取值函数、静态变量、设置函数和构造函数。

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();
public Person (int bloodGroup) {
_bloodGroup = BloodGroup.code(bloodGroup);
}
public int getBloodGroup() {
return _bloodGroup.getCode();
}
public void setBloodGroup(int arg) {
_bloodGroup = BloodGroup.code (arg);
}

我们还可以将BloodGroup中的使用整数的函数声明为private

class BloodGroup...
private int getCode() {
return _code;
}
private static BloodGroup code(int arg) {
return _values[arg];
}

posted on 2018-02-07 12:13  Sharpest  阅读(323)  评论(0编辑  收藏  举报