处理继承关系 旨在优化继承结构,消除冗余,解决继承关系不当或耦合过紧的问题,并利用多态性来简化条件逻辑。
以下是第 12 章所有重构技巧的整理、类型和说明:
技巧(中文/英文)
核心目标与动机
做法概要
示例说明
函数上移 (Pull Up Method)
消除子类中的 重复代码,将共同行为从子类移动到超类中,从而简化代码结构,使程序更容易理解。
确保待提升的函数在子类中是完全一致的。检查其引用的元素(函数调用、字段)都能从超类中调用到。将函数复制到超类,然后移除子类中的函数。
将 Employee 和 Department 子类中都存在的 annualCost 函数,提升到共同的超类 Party 中,以消除重复计算年成本的逻辑。
字段上移 (Pull Up Field)
当子类中存在 重复的字段 或字段对于超类的某个(已提升或待提升的)行为至关重要时,应将其移动到超类中。
确保所有引用该字段的函数都已处理(可能已提升)。将字段声明移动到超类,并移除子类中的声明。
将 Salesman 和 Engineer 子类中都使用的 name 字段提升到 Employee 超类中,因为 Employee 类中的某些行为(如 annualCost)可能需要用到它。
构造函数本体上移 (Pull Up Constructor Body)
如果子类的构造函数中有 公共代码,应将其移动到超类构造函数中,以避免重复。
使用 移动语句 将子类构造函数中的公共语句移动到 super() 调用之后。逐一移除公共代码,并将其引用的变量作为参数传递给超类构造函数。
将 Employee 和 Department 构造函数中对 name 字段的初始化逻辑,移动到超类 Party 的构造函数中,并传入 name 参数。
函数下移 (Push Down Method)
如果超类中的某个函数只与一个(或少数几个)子类有关,则应将其搬移到真正关心它的子类中去,以避免 被拒绝的遗赠。
将超类中的函数本体复制到每一个需要它的子类中。删除超类中的函数。从不需要它的子类中删除该函数。
如果 Employee 超类中的 quota 函数只对 Salesman 子类有意义,则将其下移到 Salesman 中。
字段下移 (Push Down Field)
如果某个字段只被一个子类(或一小部分子类)用到,就将其搬移到需要该字段的子类中,以避免超类承担不必要的责任。
在所有需要该字段的子类中声明该字段。将该字段从超类中移除。
如果 Employee 超类中的 quota 字段只被 Salesman 子类用到,则将其下移到 Salesman 中。
以子类取代类型码 (Replace Type Code with Subclasses)
当类中包含一个 类型码(type code)字段,且该字段的值决定了程序的不同行为时(重复的 switch),应引入子类和多态来取代条件逻辑。
为类型码的每个值创建相应的子类。使用 以工厂函数取代构造函数 来实例化正确的子类。将与类型码相关的条件逻辑通过 以多态取代条件表达式 移动到子类中。
将基于员工类型码(如 “engineer”、“manager”)的 switch 逻辑替换为 Engineer、Manager 等子类,用多态处理各自特有的行为。
移除子类 (Remove Subclass)
如果一个子类不再带来足够的结构或价值(冗赘的元素),或者其特有行为已不再重要,就应将其与超类合并。
使用 字段上移、字段下移、函数上移 和 函数下移 将所有元素都移到同一个类中。调整所有对子类的引用点,使其引用合并后的类,然后移除子类。
如果一个 Salesman 子类与 Employee 超类之间差异不大,则将其合并到 Employee 中。
提炼超类 (Extract Superclass)
当两个或多个类有 共同的行为或数据 时,提炼出一个共同的超类,以消除重复代码。
创建一个空的超类,让现有类继承它。使用 字段上移 搬移共同数据,使用 函数上移 搬移共同行为。
将 Employee 和 Department 中共同的 name 字段和 annualCost 行为提炼到一个新的 Party 超类中。
折叠继承体系 (Collapse Hierarchy)
如果一个类与其超类 差异不大,不值得再作为独立的类存在,则应将其合并起来。
选择合适的类名,将所有元素都移动到选中的类中。调整所有引用点,使其引用合并后留下的类,然后移除目标类。
如果 Salesman 子类与 Employee 超类在功能上没有实质区别,则可以将其合并(折叠)。
以委托取代子类 (Replace Subclass with Delegate)
当继承关系 不当 或 过于紧密 (3.23),或者对象需要 动态地改变类型 时,使用委托来取代继承,以降低耦合度。
创建一个委托类,它接受指向超类的反向引用以及子类特有的数据。将子类特有的函数和数据搬移到委托类中,并在超类中添加一个委托字段和分发逻辑。
将 PremiumBooking 子类替换为一个 PremiumBookingDelegate 对象,该委托对象在 Booking 类内部被引用,以处理高级预订的特有行为,同时允许 Booking 对象动态转换预订类型。
以委托取代超类 (Replace Superclass with Delegate)
当子类继承了超类,但 不需要或不适用 超类的所有函数,或者子类与超类之间的耦合过强时。
在子类中新建一个字段引用超类的一个对象(委托对象)。针对超类的每个函数,在子类中创建一个 转发函数,将调用请求转发给委托引用。完成后,移除继承关系。
Scroll 类不应该继承 CatalogItem(因为卷轴是目录项的实例)。通过创建 Scroll 上的字段引用 CatalogItem 实例,并转发 id、title 等访问,从而消除不当的继承关系。
这些技巧的核心在于,通过 上移/下移 (Pull Up/Push Down) 来优化既有层次结构,通过 提炼/折叠 (Extract/Collapse) 来创建或简化层次结构,并通过 多态/委托 (Polymorphism/Delegate) 来处理类型变化和降低类间耦合。
 
学习笔记——《新摄影笔记》:曝光基础学习笔记——《重构改善现有代码2》:重构API