22中常见的代码坏味道
Duplicated Code(重复代码)
解决方式:
1:同一个类的两个函数含有相同的表达式,采用Extract Method;
2:两个互为兄弟的子类中内含有相同的表达式,采用Extract Method,然后在对提炼出来的代码使用Pull Up Method,将他推入超类中;
3:两个毫无关系的类出现代码重复,应该考虑对其中一个类使用Extract Method,将重复代码提炼到一个独立的类中,然后在另一个类内使用这个新类;
Long Method(过长的函数)
遵循原则:
每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途命名;
解决方法:
1:将过长的函数变小,采用Extract Method;
如果函数内有大量的临时变量,它们会对你的函数提炼形成一种障碍;如果你用Extract Method,最终将会把很多参数和临时变量当做参数,传递给被提炼出来的新函数,导致可读性几乎没有提升;
消除临时变量的方法:
1:Replace Temp with Query
2:Introduce Parameter Object
3:Preserve Whole Object
4:Replace Method with Method Object
提炼方法技巧:
1:寻找注释
2:条件表达式和循环表达式
Large Class(过大的类)
解决方法:
运用Extract Class或者Extract subClass将几个变量一起提炼至一个新类内,提炼时应该选择类内彼此相关的变量,将它们放到一起;
Long Parameter List(过长参数列)
解决方法:
1:Introduce Parameter Object
2:Preserve Whole Object
3:Replace Parameter with Method
Divergent Change(发散式变化)
解决方法:
针对某一外界变化的所有相应修改,都只应该发生在单一类中,而这个新类内的所有内容都应该反映此变化;
你应该找出某特定原因而造成的所有变化,然后运用Extract Class将它们提炼到另一个类中;
Shotgun Surgery(霰弹式修改)
解决方法:
Divergent Change是指:一个类受多种变化的影响;
Shotgun Surgery是指:一种变化引发多个类相应的修改;
使用Move Method和Move Field把所有的修改放进同一个类,如果眼下没有合适的类可以安置这些代码,就创造一个。通常可以运用Inline Class把一系列相关行为放进同一个类
Feature Envy(依恋情节)
现象:
函数对某个类的兴趣高过对自己所处类的兴趣;(一般都是数据引起的原因)某个函数为了计算某个值,从另一个对象哪儿调用几乎半打的取值函数
解决方法:
使用Move Method将函数移至另一个地点,有时候函数中只有一部分受这种依恋之苦,这种时候你应该使用Extract Method把这一部分函数提炼到独立的函数中,再使用Move Method带它去该去地方;
如果一个函数会用到几个类的功能,使用的原则是:判断哪个类拥有最多被此函数使用的数据,然后把这个函数和那些数据摆在一起;
对抗坏味道Divergent Change,最基本的原则是:将总是一起变化的东西放在一块儿。
Data Clumps(数据泥团)
解决方法:
两个类中相同的字段,许多函数签名中相同的参数。这些总是绑在一起出现的数据真应该拥有属于它们自己的对象;首先请找出这些数据以字段形式出现的地方,运用Extract Class将它们提炼到一个独立对象中;然后将注意力转移到函数签名上,运用Introduce Parameter Object Preserve Whole Object为它减肥;这么做的直接好处是可以将函数很多的参数列缩短,简化函数的调用;
Primitive Obsession(基本类型偏执)
解决方法:
1:结合数值和币种的money类
2:由一个起始值和一个结束值组成的range类
3:由电话号码或邮政编码的number类
如果以上三种情况运用Replace Data Value with Object将原本单独存在的数据替换为对象;
如果想要替换的数据值是类型码,可以运用Replace Type Code with Class将它替换;
如果你有与类型码相关的条件表达式,可运用Replace Type code with Subclass或者Replace Type code with State/Stategy
Switch Statements(switch惊悚现身)
解决方法:
少用switch(或case)语句,从本质上说,switch语句问题在于重复;
大多数的时候,一看到switch语句,你就应该考虑以多态来替换它;问题是多态该出现在什么地方;
switch语句常常根据类型码进行选择,你要的是,"与该函数码相关的函数或类",所以应该使用Extract Method将switch提炼到一个独立函数中,再以Move Method将它搬移到需要多态性的那个类里;此时你必须决定是否使用Replace Type code with Subclass或者Replace Type code with State/Stategy,一旦这样完成继承结构之后,你就可以运用Replace Conditional with Polymorphism了;
Parallel Inheritance Hierarchies(平行继承体系)
解决方法:
在这种情况下,每当你为每某个类增加一个子类,必须也为另一个类相应增加一个子类;如果你发现某个继承体系的类名称前缀和另一个继承体系的类名称前缀完全相同,便问道了这种坏味道;
让一个继承体系的实例引用一个继承体系的实例,如果再接再厉运用Move Method和Move Field,就可以引用端的继承体系消弭于无形;
Lazy Class(冗赘类)
解决方法:
如果某些子类没有做足够的工作,试试Collapse Hieracchy(折叠继承体系),对于几乎没用的组件,你应该以Inline Class对付它们;
Speculative Generality(夸夸其谈未来性)
解决方法:
我想我们总有一天需要做这事,并因而企图以各式各样的钩子和特殊情况来处理一些非必要的事情,这种坏味道就出现了,那么做的结果往往造成体系更难理解和维护;如果所有装置都会被用到,那就值得那么做,如果用不到,就不值得。用不上的装置会挡你的路;
如果你的某一个抽象类其实没有太大的作用,运用Collapse Hieracchy。不必要的委托可运用Inline Class除掉;
如果函数的某些参数未被用上,可对它实施Remove Parameter;
如果函数名称带有多余的抽象