重构第十一章

来源:互联网 发布:通联数据待遇怎么样 编辑:程序博客网 时间:2024/06/06 03:50

第十一章、处理概括关系(即继承关系)

       有一批重构手法专门用来处理概括关系(即继承关系),主要是将函数上下移动于继承体系之中字段上移和方法上移都用于将特性向继承体系的上端移动,字段下移和方法下移则将特性向继承体系的下端移动。构造函数比较难以向上拉动,因此专门有一个构造函数本体上移处理它,一般不会将构造函数往下推,因为以工厂函数取代构造函数通常更管用。

11.1、字段上移

什么时候用?

两个子类拥有相同的字段

怎么用?

将该字段上移

具体步骤:

1、针对待提升字段,检查它们的所有被引用点,确认它们以同样的方式被使用。

2、如果这些字段的名称不同,先将它们改名,使每一个名称都和你想为超类字段取的名称相同。编译,测试。

3、在超类中新建一个字段。(如果子类的字段是private的,必须将超类的字段声明为protected,这样子类才能访问)

4、移除子类中的字段。编译,测试。

5、考虑对超类的新建字段使用自封装字段

 

11.2、函数上移

什么时候用?

有些函数,在各个子类中产生完全相同的效果

怎么用?

将该函数移至超类

具体步骤:

1、检查待提升函数,确定它们完全一致。(如果有些函数看上去做了相同的事,但并不完全一致,可以使用替换算法让它们变得一致)

2、如果待提升函数的签名不同,将那些签名都修改为想要在超类中使用的签名

3、在超类新建一个函数,将某一个待提升函数的代码复制到其中,做适当调整然后编译(如果使用的是一种强类型语言,而待提升函数又调用了一个只出现在子类而未出现在超类的函数,此时可以在超类中为被调用函数声明一个抽象函数)

4、移除一个待提升的子类函数编译并测试

5、逐一移除待提升的子类函数,直到只剩下超类中的函数为止,每次移除之后都需要测试。

6、观察该函数的调用者,看看是否可以改为使用超类类型的对象

 

11.3、构造函数本体上移

什么时候用?

在各个子类中拥有一些构造函数,他们的本体几乎完全一致

怎么用?

在超类中新建一个构造函数,并在子类构造函数中调用它

具体步骤:

1、在超类中定义一个构造函数

2、将子类构造函数中共同的代码搬移到超类构造函数中(被搬移的可能是子类构造函数的全部内容,首先设法将共同代码搬移到子类构造函数的起始处,然后复制到超类构造函数中)

3、将子类构造函数中共同的代码删掉,改而调用新建的超类构造函数。(如果子类构造函数中的所有代码都是一样的,那么子类构造函数只需调用超类构造函数)

4、编译,测试(如果日后子类构造函数再出现共同代码,可以首先使用提炼函数将那一部分提炼到一个独立函数,然后使用函数上移将该函数上移到超类)

 

11.4、函数下移

什么时候用?

超类中的某个函数只与部分(而非全部)子类有关

怎么用?

将这个函数移到相关的子类去

具体步骤:

1、在所有子类中声明该函数,将超类中函数本体复制到每一个子类函数中

2、删除超类中的函数,编译并测试

3、将该函数从所有不需要它的那些子类中删掉,编译测试。

 

11.5、字段下移

什么时候用?

超类中的某个字段只被部分(而非全部)子类用到

怎么用?

将这个字段移到需要它的那些子类去

具体步骤:

1、在所有子类中声明该字段

2、将该字段从超类中删除,编译测试。

3、将该字段从所有不需要它的那些子类中删掉,编译测试。

 

11.6、提炼子类

什么时候用?

类中的某些特性只被某些(而非全部)实例用到

怎么用?

新建一个子类,将上面所说的那一部分特性移到子类中

具体步骤:

1、为源类定义一个新的子类

2、为这个新的子类提供构造函数(简单的做法是:让子类构造函数接受与超类构造函数相同的参数,并通过super调用超类的构造函数,如果希望对用户隐藏子类的存在可以使用以工厂函数取代构造函数)

3、找出调用超类构造函数的所有地点,如果他们需要的是新建的子类,令他们改而调用新构造函数

4、逐一使用下移函数和下移字段将源类的特性移到子类去。

5、找到所有这样的字段:它们所传达的信息如今可由继承体系自身传达(这一类字段通常是Boolean变量或类型码)。以自封装字段避免直接使用这些字段,然后将它们的取值函数替换为多态常量函数。所有使用这些字段的地方都应该以以多态取代条件表达式重构。(任何函数如果位于源类之外,而又使用了上述字段的访问函数,考虑搬移函数将它移到源类中,然后再使用以多态取代条件表达式)

6、每次下移之后,编译并测试

 

11.7、提炼超类

什么时候用?

两个类有相似的特性

怎么用?

为这两个类建立一个超类,将相同特性移至超类

具体步骤:

1、为原本的类新建一个空白的抽象超类

2、运用字段上移、方法上移和构造函数本体上移逐一将子类的共同元素上移到超类(先搬移字段,通常比较简单。如果相应的子类函数有不同的签名,但用途相同,可以先使用函数改名将它们的签名改为相同,然后再使用函数上移。如果相应的子类函数有相同的签名,但函数本体不同,可以在超类中把它们的共同签名声明为抽象函数)

3、每次上移后,编译并测试

4、检查留在子类中的函数看它们是否还有共同的成分,如果有,可以使用提炼函数将共通部分再提炼出来,然后使用函数上移将提炼出的函数上移到超类。如果各个子类中某个函数的整体流程很相似,可以使用塑造模板函数

5、将所有共通元素都上移到超类之后,检查子类的所有用户。如果它们只使用共同接口,就可以把它们请求的对象类型改为超类

 

11.8、提炼接口

什么时候用?

若干客户使用类接口中的同一子集,或者两个类的接口有部分相同

怎么用?

将相同的子集提炼到一个独立的接口中

具体步骤:

1、新建一个空接口

2、在接口中声明待提炼类的共通操作

3、让相关的类实现上述接口

4、调整客户端的类型声明,令其使用该接口

 

11.9、折叠继承体系

什么时候用?

超类和子类之间没有太大的区别

怎么用?

将它们合为一体

具体步骤:

1、选择想要移除的类:超类还是子类?

2、使用字段上移和方法上移,或者方法下移和字段下移,把想要移除的类的所有行为和数据搬移到另一个类。

3、每次移动后,编译并测试

4、调整即将被移除的那个类的所有引用点,令它们改而引用合并后留下的类。这个动作将会影响变量的声明、参数的类型以及构造函数。

5、移除目标类,此时应该已经成为一个空类,编译测试。

 

11.10、塑造模板函数

什么时候用?

有一些子类,其中相应的某些函数以相同顺序执行类似的操作,但各个操作的细节上有所不同

怎么用?

将这些操作分别放进独立函数中,并操持它们都有相同的签名,于是原函数也就变得相同了,然后将原函数上移至超类。

具体步骤:

1、在各个子类中分解目标函数,使分解后的各个函数要么完全相同要么完全不同。

2、运用方法上移将各子类内完全相同的函数上移至超类

3、对于剩余的存在各子类里完全不同的函数,实施函数改名,使所有这些函数的签名完全相同。

4、修改上述签名后,编译测试

5、运用方法上移将所有原函数逐一上移至超类,在超类中将那些代表各种不同的操作的函数定义为抽象函数,编译测试。

6、移除其他子类中的原函数,每删除一个,编译并测试。

 

11.11、以委托取代继承

什么时候用?

某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据

怎么用?

在子类中新建一个字段用以保存超类,调整子类函数,令它改而委托超类,然后去掉两者之间的继承关系。

具体步骤:

1、在子类中新建一个字段,使其引用超类的一个实例,并将它初始化为this

2、修改子类内的所有函数,让他们不再使用超类,转而使用上述那些受托字段,每次修改后编译并测试。(不能这样修改子类中通过super调用超类函数的代码,否则它们会陷入无限递归,这种函数只有在继承关系被打破后才能修改)

3、去除两个类之间的继承关系,新建一个受托类的对象赋给受托字段

4、针对客户端所用的每一个超类函数,为它添加一个简单的委托函数,编译测试。

 

11.12、以继承取代委托

什么时候用?

在两个类之间使用委托关系,并经常为整个接口编写许多极简单的委托函数。

怎么用?

让委托类继承受托类

具体步骤:

1、让受托端成为受托端的一个子类,编译

2、将受托字段设为该字段所处对象本身

3、去掉简单的委托函数,编译并测试

4、将所有其他涉及委托关系的代码,改为调用对象本身

5、移除受托字段

 

原创粉丝点击