重复代码(Duplicated Code)
代码的坏味道中,重复代码是首当其冲的坏味道,如果在一个以上的地方看到相同的代码结构(很多时候是由于复制粘贴逻辑),那么可以肯定:将他们合而为一,程序将会更好。
处理方法: 用Extra Method 提炼重复逻辑到一个新方法,供需要的地方调用。
①重复逻辑位于兄弟类或者父子类中:将重复逻辑提炼到父类中
②重复逻辑位于同一个类中:将重复逻辑提炼到一个私有方法
③重复逻辑位于完全无关的两个类:将重复逻辑提炼到一个类中,供两者调用。
优点: 便于维护,若逻辑发生变动,仅修改提炼的方法即可,否则需要去所有调用处修改逻辑,时间成本大,还有可能出现遗漏的情况。
过长函数(Long Method)
根据单一职责原则,一个类的方法所拥有的职责尽量不要复杂,若出现逻辑复杂,代码量过大的过长函数,需要将他们分解提炼成其他方法调用。
处理方法: 用Extra Method 根据代码的职责和目的分类提炼方法。(条件表达式和循环常常是提炼的讯号)
优点: 增强代码的可读性,便于维护。
过大类(Large Class)
如果想利用类做太多事情,其内往往就会出现许多实例变量,重复代码因此就容易出现了。
处理办法: 用Extra Class 或 Extra SubClass 提炼类,提炼时应选择彼此相关的变量。
过长参数列表(Long Parameter List)
方法中有过长的参数列表,不易使用。
处理方法: 将相似参数封装到一个参数类中,用该类作为入参。
发散式变化(Divergent Change)
如果加一种数据库,我得修改一个类中的3个方法,如果添加一种金融工具,我需要修改4个方法。那么也许将这个对象分成两个类会更好,这样每个对象就只会因为一种变化而发生修改。
处理方法: 因为不同变化而需要变动的方法可以分别提炼到一个类中。
散弹式修改(Shotgun Surgery)
每遇到某种变化,你都得在不同的类中做一些修改。
处理方法: 将因为变化需要修改的逻辑整合提炼到一个类中。
依恋情结(Feature Envy)
某个方法为了计算某个值,利用一堆另一个类的取值方法获取了许多的相关值。应当将总是一起变化的东西放在一起。
处理方法: 将该方法移到另一个类中。
数据泥团(Data Clumps)
常常会看到许多相同的数据项,例如许多类中的相同字段,方法的相同入参。
处理方法: 将这些数据项提炼到一个类中。
基本类型偏执(Primitive Obsession)
如果你发现你正从数组中挑选参数,可以尝试将数组转换为对象。有一些基本类型总是成对出现,可以考虑封装成对象参数。
处理方法: 将这些基本类型数据提炼到一个类中。
switch statements
面向对象的特征就是少用switch语句。
处理方法 :将switch转化成多态。
冗赘类(Lazy Class)
当一个类没有做到足够的工作,或仅被一个类调用到。
处理办法:尝试将该类合并到调用它的类中。
夸夸其谈未来性(Speculative Generality)
这个代码坏味道与过早进行计划,过度设计有关。为方法定义过多的参数,实际有些字段却没用到;没有什么作用的抽象类。
处理方法:移除类,移除参数等…
暂时字段(Temporary Field)
仅在特定环境下使用的变量,在变量未被使用的情况下,猜测当初设置它的目的,是令人头疼的。
处理方法:将这些暂时变量集中到一个新类中管理。
过度耦合的消息链(Message Chains)
消息链发生于当一个客户向一个对象要求另一个对象,然后客户又向这另一对象要求另一个对象,再向这另一个对象要求另一个对象。一旦对象间的关系发生变化,客户端就不得不做出修改。
处理方法:观察消息链最终的对象的用途,提取其公用部分的方法。用方法代替消息链。
中间人(Middle Man)
过渡运用委托 一般是某个类接口有一般的函数都委托给其它类。
处理方法:如果这样不干实事的函数只有少数几个可以使用InlineMethod(117)把他们放到调用端,如果这些Middle Man还有其它行为可以运用 Replace Delegation with Inheritance(355)把它变成主类的子类。
狎昵关系(Inappropriate Intimacy)
两个类的关系过于紧密。继承往往造成过度亲密。
处理方法:划清界限拆散,或合并,或提取公用部分。