Summary: 你的各个子类的唯一差别只在“返回常量数据”的函数身上。修改这些函数,使它们返回超类中的某个(新增)字段,然后销毁子类。
Motivation: 建立子类的目的,是为了增加新特性或变化其行为。有一种变化行为被称为“常量函数”(constant method),它们会返回一个硬编码的值。这东西有其用途:你可以让不同的子类中的同一个访问函数返回不同的值。你可以在超类中将访问函数声明为抽象函数,并在不同的子类中让它返回不同的值。
尽管常量函数有其用途,但若子类中只有常量函数,实在没有足够的存在价值。你可以在超类中设计一个与常量函数返回值相应的子弹,从而完全去除这样的子类。如此一来就可以避免因继承而带来的额外复杂性。
Mechanics:
1. 对所有子类使用Replace Constructor with Factory Method.
2. 如果有任何代码直接引用子类,令它改而引用超类。
3. 针对每个常量函数,在超类中声明一个final字段
4.为超类声明一个protected构造函数,用以初始化这些新增字段。
5. 新建或修改子类构造函数,使它调用超类的新增构造函数。
6.编译,测试。
7.在超类中实现所有常量函数,令它们返回相应字段值,然后将该函数从子类中删掉
8.没删除一个常量函数,编译并测试。
9.子类中所有的常量函数都被删除后,使用Inline Method将子类构造函数内联到超类的工厂函数中。
10.编译,测试。
11. 将子类删掉。
12. 编译,测试
13. 重复“内联构造函数、删除子类”过程,知道所有子类都被删除。
范例:
本例之中,我们以Person表示“人”,并针对每种性别建立一个子类:以Male子类表示“男人”,以Female子类表示“女人”:
abstract class Person{
abstract boolean isMale();
abstract char getCode();
...
class Male extends Person{
boolean isMale(){
return true;
}
char getCode(){
return "M";
}
}
class Female extends Person{
boolean isMale(){
return false;
}
char getCode(){
return "F";
}
}
}
在这里,两个子类之间唯一的区别就是:它们以不同的方式实现了Person所声明的抽象函数getCode(),返回不同的硬编码常量(所以getCode()是个长啦ing函数)。我们应该将这两个子类去掉。
首先需要使用Replace Constructor with Factory Method。在这里,我们需要为每个子类建立一个工厂函数:
class Person...
static Person createMale(){
return new Male();
}
static Person createFemal(){
return new Female();
}
然后把对象创建过程从以下这样:
Person kent = new Male();
改为这样:
Person kent = Person.createMale();
将所有调用构造函数的地方都修改为调用工厂函数之后,就不应该再有任何对子类的直接引用了。一次全文搜索就可以帮助我们证实这一点。然后,我们可以把这两个子类都声明为private,这样编译器就可以帮助我们,保证至少包外不会有任何代码使用它们。
现在,针对每个常量函数,在超类中声明一个对应的字段:
class Person ...
private final boolean _isMale;
private fianl char _code;
然后为超类加上一个protected构造函数:
class Person ...
protected Person(boolean isMale, char code){
_isMale = isMale;
_code = code;
}
再为子类加上新构造函数,令它调用超类新增的构造函数:
class Male ...
Male(){
super(true, 'M');
}
class Female ...
Female(){
supre(false, 'F');
}
完成这一步后,编译并测试。所有字段都被创建出来并被赋予初值,但到目前为止,我们还没有使用它们。现在我们可以在超类中加入访问这些字段的函数,并删掉子类中的常量函数,从而让这些字段登场:
class Person ...
boolean isMale(){
return _isMale;
}
我们可以逐一对每个字段、每个子类进行这一步骤的的修改,也可以采取一次性全部修改的手段。
所有字段都处理完毕后,所有子类也都空空如也了,于是可以删除Person中那个抽象函数的abstract修饰符,并以Inline Method将子类构造函数内联到超类的工厂函数中:
calss Pserson ...
static Person createMale(){
return new Person(true, 'M');
}
编译,测试后,就可以删掉Male类,并对Female类重复上述过程。
来源:oschina
链接:https://my.oschina.net/u/134516/blog/212672