08.重构-处理类的继承关系(generalization)

1. 问题及方案

  • 字段位置不正确:Pull Up Field、Pull Down Field;
  • 函数位置不正确:Pull Up Method、Pull Down Method;
  • 构造函数:Pull Up Constructor Body(向上)、Replace Constructor with Factory Method;
  • 函数大体相同、细节不同:Form Template Method;
  • 改变继承体系:Extract Subclass、Extract Superclass、Extract Interface;
  • 继承体系部分类无用:Collapse(瓦解) Hierarchy(层次结构);
  • 委托替代继承:Replace Inheritance with Delegation;
  • 继承替代委托:Replace Delegation with Inheritance;

2. Pull Up Field/Method(字段/函数上移)

将多个子类的相同字段/函数移到超类。

3. Pull Down Field/Method(字段/函数下移)

超类的字段/函数只与部分(而非全部)子类有关,移动到相关子类中。

4. Pull Up Constructor Body(构造函数本体上移)

多个子类的构造函数相同,将主体移动到超类构造函数中,并在子类中调用它。

5. Replace Constructor with Factory Method(使用工厂方法替代构造函数)

由于无法将构造函数本体下移,故改为使用工厂方法模式。

6. Extract Subclass(提炼子类)

问题:类中的某些特性只被某些(而非全部)实例使用。
新建一个子类,移动特性到子类中。
ps:Extract Class 是另一种选择,两者抉择之处在于委托和继承之间的选择。

7. Extract SuperClass(提炼超类)

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

8. Extract Interface(提炼接口)

多个类有相似的行为,或多个类的接口有相似部分,将相同的行为提炼到一个独立的接口中。

9. Collapse Hierarchy(折叠继承体系)

问题:超类和子类之间无太大区别。
将它们合为一体。

10. Form Template Method(塑造模板函数)

问题:子类的某些函数以相同顺序执行类似操作,细节有所不同。
将这些操作分别放进独立函数中,并保持相同签名。而后将原函数提炼到超类中。
ps:即模板方法模式。

11. Replace Inheritance with Delegation(以委托取代继承)

问题:某个子类只使用超类的一部分,或根本不需要继承而来的数据。
在子类中新建一个字段引用超类,调整子类函数,而后让它调用超类,最后去除两者之间的继承关系。
ps:此处的委托其实应该理解为委托调用关系,即依赖关系,而非 C# 的委托。

12. Replace Delegation with Inheritance(以继承取代委托)

问题:两个类之间使用委托关系,并经常为了整个接口(即所有函数)编写许多极其简单的委托函数。
让委托类继承被委托类。
ps

  • 该重构手法与 Replace Inheritance with Delegation 恰恰相反。
  • 如果你并没有使用被委托类的所有函数,就不该使用该重构手法。
  • 被委托对象被不止一个对象共享,而且被委托对象是可变的,此时就不该使用该重构手法。

参考

  • 《重构-改善既有代码的设计》(第11章)
坚持原创技术分享,您的支持将鼓励我继续创作!