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];
}