平行继承体系(parallel Inheritsnce hierarchies)
是Shotgun surgery的特殊情况,每当为某一个类增加一个子类,必须为另一个类增加子类,如果发现某个继承体系的类名前缀和另一个继承体系的类名前缀完全相同,就闻到了坏味道。
解决方案:让一个继承体系的实例引用另一个继承体系的实例,再使用move method 和,move field,将引用端的继承体系消弭于无形
冗赘类(Lazy Class)
如果有一个类的所得不值其身价,就应该消失,比如某个类原本对得起它自己的价值,但是重构使它身形缩水,不再做那么多工作,或者开发前规划了某些变化,添加一个类来应对变化,但实际上没有发生这种变化。如果子类没有做足够的工作,试试Collapse hierarchy,对于没有用的组件,用Inline Class进行处理
夸夸其谈未来性(Sepculative Generality)
想到一些情况,觉得总有一天需要做这个事情,然后企图以各式各样的钩子和特殊情况来处理一些非必要的事情,形成坏味道,这样会造成系统更难理解和维护,用不上的配置应搬开。如果都能用上,那这么做就是值得的。如果函数或类的唯一用户是测试用例,请先确认它们的用途是否帮主测试用例检测正当功能,如果不是,请连同测试用例一并删掉。
令人迷惑的暂时字段(Tempoary Field)
如果某个实例变量仅为某种特定情况而设,请使用Extract class把所有和这个变量相关的代码都放到一个新类里面,还可以用 introduce null object在变量不合法的情况下创造一个null 对象,从而避免写出条件式代码
如果一个复杂需要好几个变量,可以利用Extract class 把这些变量和相关函数提炼到一个独立类中。
过度耦合的消息链(Message Chains)
如果看到用户向一个对象请求另一个对象,然后再向后者请求另一个对象,然后再再请求另一个对象。。。这就是消息链。这样客户代码将与查找过程中的导航机构紧密耦合,一旦对象间的关系发生任何变化,客户端就不得不做出相应修改
解决方案:先观察消息链最终得到的对象是用来干什么的,看看能否以Extract method把使用该对象的代码提炼到一个独立函数中,再运用move medthod 把这个函数推入消息链。
中间人(middle man)
对象的基本特征之一就是封装--对外部世界隐藏其内部细节,封装往往伴随着委托。如果一个类接口有一半的函数都委托给其他类,这就是过度委托,这时应该使用remove middle man,直接和真正负责的对象打交道。
狎昵关系(inappropriate intimacy)
如果两个过于亲密,可以采用move medthod 和move field帮他们划清界限,减少狎昵行径。也可以用change bidirectional association to unidirection 让其中一个类对另一个类斩断情丝,也可以用hide delegate让另一个类来为他们传递相思情。如果需要让子类独立,可使用replace inheritance with delegation
异曲同工的类(alternative class with different interfaces)
如果两个函数做着同一件事,却有着不同的签名,请运用rename method根据它们用途重新命名,然后反复运用move method 将某些行为移入类,直到两者协议一致为止。
不完整的库类(incomplete library class)
如果只修改库类的一两个函数,可以运用introduce foreign method
如果想要添加一大推额外行为,就得运用introduce local extension
纯稚的数据类(data class)
data class 指它们拥有一些字段,以及用于访问(读写)这些字段的函数,是一种不会说话的数据容器
public字段应使用encapsulate field封装起来
容器类字段应使用encapsulate collection 封装起来
不被其他类修改的字段,应运用remove setting method
被拒绝的遗赠(redused bequest)
过多的注释(comments)
过多的注释以为这代码很糟糕,我们需要利用各种重构收费把坏味道去除
如果需要用注释来解释代码做了什么,用extract method
如果函数已经提取出来,需要用注释来解释行为,用rename method
如果注释是说明某些系统的需求规格,用intrduce assertion
当你感觉需要撰写注释时,请先尝试重构,试着让左右注释都变得多余