重复代码Duplicated Code
臭味集合里面排第一的就是重复代码了。如果你在不止一处发现了同样结构的代码,你可以确定如果你找到一种方法来统一他们的话,你的程序将会改善。
最简单的重复代码问题是当你在同一个类中有两个方法有相同的表达时出现的。那么你需要做的所有步骤只是提取方法然后在两处调用代码。
另一种常见的重复问题是当你在两个兄弟类中有相同的表达。你可以通过在两个类中提取方法然后拉升方法(Pull up Method)来消灭重复。如果这段代码相似但不相同,你需要通过提取方法来分离相同和不同的部分。你可能会发现你可以使用构成模版方法(Form Template Method)。如果这些方法是在用不同的算法做同样的事情,你可以选择两种算法中比较清楚的那个然后替换算法。
如果你的重复代码在两个不相关的类中,考虑在一个类中使用提取类,然后在另一个类中使用这个新部件。另一种可能是这个方法只属于其中一个类,并且要被其他类调用;或者方法属于另一个类需要参考原始类。你必须决定这个方法在哪更有意义,并且确认他只在那里不在其他任何地方。
长方法Long Method
对象程序存在的最好最长的都是那些短方法组成的。新接触对象的程序员经常觉得对象程序是无尽的委托,没有一点计算发生。当你和这样的程序相处一些年份,你会学到小方法是多么的有价值。所有间接带来的好处——解释,分享,选择都被小方法支持。
早在编程最初时期人们就意识到一段流程越长就越难被理解。老一些的语言对子程序的调用付出更多的代价,阻止了人们接触小方法。现代面对对象语言差不多消除了进程中的调用的代价。对于代码的读者仍然还有代价,就是如果要看子程序做了什么需要切换内容。开发环境允许同时看两个方法帮助消除了这个代价,但真正让理解小方法更容易的是好的命名。如果对一个方法你有好的名字,那么你就不需要看他的方法体了。
网络效应即你应该在分解方法上更积极一些。一个我们遵循的启示是,当我们觉得需要注释的时候,我们写一个方法来取代之。这样的一个方法包含被注释过的代码,但被以代码的意图命名了,而不是代码怎样做命名。我们可能对几行代码这样做,也可能只针对一行。我们这样做即使我们调用的方法比他代替的代码还要长,但提供的方法名解释代码的意图。这里的关键不是方法的长度,而是方法做什么和怎么做之间的语义距离。
百分之九十九的时候,简短方法你所需要做的全部就是提取方法。把方法中看起来很适合在一起的部分找到,然后作为一个新的方法。
如果你有一个许多参数和临时变量的方法,这些元素碍了提取方法的事。如果你试图提取方法,你以传递那么多参数和临时变量作为提取方法的参数收尾,那么这个结果几乎不比原来的状况可读性更高。你常常可以通过用请求替代临时变量来消除临时变量。一长列参数可以被引入参数对象和保留整个对象(Preserve Whole Object)来精简。
如果你尝试了并且你仍然有许多临时变量和参数,那么是时候使用重型火炮:用方法对象替代方法了。
你怎么鉴别需要被提取的代码块呢?一个好的技巧是寻找注释。注释常常是这类语义距离的信号。一块带有注释的代码告诉你,这段代码做的事可以被基于这个注释命名的方法替代。即使是一行代码也值得提取,如果它需要解释。
条件语句和循环也是提取的信号。用分解条件语句来处理条件语句表达。对待循环,提取循环和循环中的代码到他们自己的方法里去。