代码坏味道之变革的障碍
翻译自:https://sourcemaking.com/refactoring/smells/change-preventers
变革的障碍(Change Preventers)这组坏味道意味着:当你需要改变一处代码时,却发现不得不改变其他的地方。这使得程序开发变得复杂、代价高昂。
发散式变化
发散式变化(Divergent Change)
类似于霰弹式修改(Shotgun Surgery)
,但实际上完全不同。发散式变化(Divergent Change)
是指一个类受多种变化的影响。霰弹式修改(Shotgun Surgery)
是指多种变化引发多个类相应的修改。
特征
你发现你想要修改一个函数,却必须要同时修改许多不相关的函数。例如,当你想要添加一个新的产品类型时,你需要同步修改对产品进行查找、显示、排序的函数。

问题原因
通常,这种发散式修改是由于编程结构不合理或者“复制-粘贴式编程”。
解决办法
- 运用
提炼类(Extract Class)
拆分类的行为。
收益
- 提高代码组织结构
- 减少重复代码
重构方法说明
提炼类(Extract Class)
问题
某个类做了不止一件事。

解决
建立一个新类,将相关的字段和函数从旧类搬移到新类。

平行继承体系
平行继承体系(Parallel Inheritance Hierarchies)
其实是霰弹式修改(Shotgun Surgery)
的特殊情况。
特征
每当你为某个类添加一个子类,必须同时为另一个类相应添加一个子类。这种情况的典型特征是:某个继承体系的类名前缀或类名后缀完全相同。

问题原因
起初的继承体系很小,随着不断添加新类,继承体系越来越大,也越来越难修改。
解决方法
- 一般策略是:让一个继承体系的实例引用另一个继承体系的实例。如果再接再厉运用
搬移函数(Move Method)
和搬移字段(Move Field)
,就可以消除引用端的继承体系。
收益
- 更好的代码组织
- 减少重复代码
何时忽略
- 有时具有并行类层次结构只是一种为了避免程序体系结构更混乱的方法。如果你发现尝试消除平行继承体系导致代码更加丑陋,那么你应该回滚你的修改。
重构方法说明
搬移函数(Move Method)
问题
你的程序中,有个函数与其所驻类之外的另一个类进行更多交流:调用后者,或被后者调用。

解决
在该函数最常引用的类中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数,或是旧函数完全移除。

搬移字段(Move Field)
问题
在你的程序中,某个字段被其所驻类之外的另一个类更多地用到。

解决
在目标类新建一个字段,修改源字段的所有用户,令他们改用新字段。

霰弹式修改
霰弹式修改(Shotgun Surgery)
类似于发散式变化(Divergent Change)
,但实际上完全不同。发散式变化(Divergent Change)
是指一个类受多种变化的影响。霰弹式修改(Shotgun Surgery)
是指多种变化引发多个类相应的修改。
特征
任何修改都需要在许多不同类上做小幅度修改。

问题原因
一个单一的职责被拆分成大量的类。
解决方法
- 运用
搬移函数(Move Method)
和搬移字段(Move Field)
来搬移不同类中相同的行为到一个独立类中。如果没有适合存放搬移函数或字段的类,就创建一个新类。 - 通常,可以运用
将类内联化(Inline Class)
将一些列相关行为放进同一个类。

收益
- 更好的代码组织
- 减少重复代码
- 更易维护

重构方法说明
搬移函数(Move Method)
问题
你的程序中,有个函数与其所驻类之外的另一个类进行更多交流:调用后者,或被后者调用。

解决
在该函数最常引用的类中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数,或是旧函数完全移除。

搬移字段(Move Field)
问题
在你的程序中,某个字段被其所驻类之外的另一个类更多地用到。

解决
在目标类新建一个字段,修改源字段的所有用户,令他们改用新字段。

将类内联化(Inline Class)
问题
某个类没有做太多事情。

解决
将这个类的所有特性搬移到另一个类中,然后移除原类。
