二十一种代码坏味道

     如何评价怎样的代码是好的,一直都是争论性的,有人说效率第一,有人说维护扩展第一,我曾经在一家公司做PHP开发,期间跟过两个老大,第一个要求拼接字符串时必须使用 sprintf 函数,另一个要求拼接字符串不要使用任何函数,直接用 ".";搞笑的是在一次代码review讨论会时,两人杠上了,很明显使用sprintf函数时代码美观,易于维护,但的确是消耗了时间,尤其是并发量大的网站中使用时,感觉明显;但使用“.”呢,执行效率没问题,一个字--快,但对于动态网站代码修改维护是经常的事,一个用“.”拼接起来的字符串,让你维护时,能让你头疼死;你说到底谁说的对,结果单位那次开会去了2、3十人,结果在这两个人观点中间排队时,人数相等,各占一半(不排除有些人巴结领导)。
   上面说的只是想表达,好的代码在小范围内内很难评价,但是大的方向却是可以明确地,执行效率高又美观好维护,这样的代码当然是谁都想看到的,但两者往往相冲突。
   但坏的代码却是,显而易见的,效率即差有难维护重构,谁然有人说这样的代码只有在项目代码完成之后才能评价代码的优劣性,但是质量差的代码在慢慢变坏前就会渐渐的发出变坏的味道,就像食物,坏掉的食物也不是立马就由好变坏的,他有个过程,在这个过程中会渐渐散发出一种由淡变浓的味道,代码也是一样,当我们在写代码是遇到嗅到这样的坏气味时,就要告诉自己,代码是不是要改一改了。
   说了那么多废话,下方面我把从网上down下来的代码的21中坏味道贴出来,大家共同学习,也希望大家都能写出效率高有健壮性强的代码来:
1.Duplicated Code(重复性代码)
    代码重复几乎是最常见的异味了。他也是Refactoring 的主要目标之一。代码重复往往来自于copy-and-paste 的编程风格。与他相对应OAOO (Once And Only Once)是一个好系统的重要标志。如果你觉得有些代码需要重复出现,则考虑它是不是该单独挪出来作为一个功能函数考虑了。
2.Long method(冗长的方法)
    它是传统结构化的“遗毒“。一个方法应当具有自我独立的意图,不要把几个意图放在一起,我的《大类和长方法》一文中有详细描述。这在一般的出现情况中,往往是代码编写这把自己函数所需要的要功能写进函数体内,完全忽略了自己函数的原本共,使原本功能比例弱化。如果真出现这种情况,还不如如写个类去了。
3.Large Class(庞杂类)
    大类就是你把太多的责任交给了一个类。这里的规则是One Class One Responsibility,这和冗长方法一个概念,不能使自己的类专一的做某一件事情。
4.Divergent Change(奇异性变化)
    一个类里面的内容变化率不同。某些状态一个小时变一次,某些则几个月一年才变一次;某些状态因为这方面的原因发生变化,而另一些则因为其他方面的原因变一次。面向对象的抽象就是把相对不变的和相对变化相隔离。把问题变化的一方面和另一方面相隔离。这使得这些相对不变的可以重用。问题变化的每个方面都可以单独重用。这种相异变化的共存使得重用非常困难。这种状况也就是类中的方法功能相互混淆。方法间关联性太强,变得调一方法而动全类的情况发生。
5.Shotgun Surgery(中了散弹枪式的外壳手术)
    这正好和上面相反。对系统一个地方的改变涉及到其他许多地方的相关改变。这些变化率和变化内容相似的状态和行为通常应当放在同一个类中。
6.Feature Envy(特性嫉妒)
    对象的目的就是封装状态以及与这些状态紧密相关的行为。如果一个类的方法频繁用get 方法存取其他类的状态进行计算,那么你要考虑把行为移到涉及状态数目最多的那个类。也就是说A类老看着B累的功能好自己拿来使用,如果这种状况很多的话,还不如去点A类,将这些功能直接写进B类的好。
7.Data Clumps(数据/参数扎堆)
    某些数据通常像孩子一样成群玩耍:一起出现在很多类的成员变量中,一起出现在许多方法的参数中…..,这些数据或许应该自己独立形成对象。
8.Primitive Obsession(变量类型强迫症)
    面向对象的新手通常习惯使用几个原始类型的数据来表示一个概念。譬如对于范围,他们会使用两个数字。对于Money,他们会用一个浮点数来表示。因为你没有使用对象来表达问题中存在的概念,这使得代码变的难以理解,解决问题的难度大大增加。好的习惯是扩充语言所能提供原始类型,用小对象来表示范围、金额、转化率、邮政编码等等。
9.Switch Statement(偏执开关语句)
    基于常量的开关语句是OO 的大敌,你应当把他变为子类、state 或strategy。
10. Parallel Inheritance Hierarchies(勾肩搭背型类继承)
    并行的继承层次是shotgun surgery 的特殊情况。因为当你改变一个层次中的某一个类时,你必须同时改变另外一个层次的并行子类。
11. Lazy Class(懒散类)
    一个干活不多的类。类的维护需要额外的开销,如果一个类承担了太少的责任,应当消除它。
12. Speculative Generality(投机性空头概念)
    一个类实现了从未用到的功能和通用性。通常这样的类或方法唯一的用户是testcase。不要犹豫,删除它。别老想着,某时某时将会利用此进行扩展,这是一句以后再也想不起来的空头许诺。
13. Temporary Field(短暂性字段)
    一个对象的属性可能只在某些情况下才有意义。这样的代码将难以理解。专门建立一个对象来持有这样的孤儿属性,把只和他相关的行为移到该类。最常见的是一个特定的算法需要某些只有该算法才有用的变量。
14. Message Chain(消息链)
    消息链发生于当一个客户向一个对象要求另一个对象,然后客户又向这另一对象要求另一个对象,再向这另一个对象要求另一个对象,如此如此。这时,你需要隐藏分派。
15. Middle Man(管事太多的中间人)
    对象的基本特性之一就是封装,而你经常会通过分派去实现封装。但是这一步不能走得太远,如果你发现一个类接口的一大半方法都在做分派,你可能需要移去这个中间人。
16. Inappropriate Intimacy(过度亲密)
    某些类相互之间太亲密,它们花费了太多的时间去砖研别人的私有部分。对人类而言,我们也许不应该太假正经,但我们应当让自己的类严格遵守禁欲主义。
17. Alternative Classes with Different Interfaces(不同接口的替代类)
    做相同事情的方法有不同的函数signature,一致把它们往类层次上移,直至协议一致。这里要求的也就是相同功能性的函数向上层汇聚。要充分理解虚函数的概念。
18. Incomplete Library Class (缺陷性类库)
    要建立一个好的类库非常困难。我们大量的程序工作都基于类库实现。然而,如此广泛而又相异的目标对库构建者提出了苛刻的要求。库构建者也不是万能的。有时候我们会发现库类无法实现我们需要的功能。而直接对库类的修改有非常困难。这时候就需要用各种手段进行Refactoring。
19. Data Class(数据类,发育不良性类)
    对象包括状态和行为。如果一个类只有状态没有行为,那么肯定有什么地方出问题了。
20. Refused Bequest(自作多情型遗传)
    超类传下来很多行为和状态,而子类只是用了其中的很小一部分。这通常意味着你的类层次有问题。
21. Comments(说明书型注释)
    经常觉得要写很多注释表示你的代码难以理解。如果这种感觉太多,表示你需要Refactoring。

posted @ 2013-04-10 18:15  顺水的船  阅读(362)  评论(0编辑  收藏  举报