代码的坏味道——摘自《重构》

来源:互联网 发布:淘宝店铺年度计划表 编辑:程序博客网 时间:2024/04/28 20:26
Duplicated Code
    如果在一个以上的地点看到相同的程序结构,那么应当可以肯定:设法将它们合而为一,程序会变得更好。

Long Method
    应该更积极进取地分解函数。我们遵循这样一条原则:每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。

Large Class
    如果想利用单一class做太多事情,其内往往就会出现太多 instance 变量。一旦如此, Duplicated Code 也就接踵而至了。

Long Paramter List
    太长的参数列难以理解,太多参数会造成前后不一致,不易使用,而且一旦需要更多数据,就不得不修改它。如果将对象传递给函数,大多数据修改都没有必要,因为你很可能只需在函数内增加一两条请求,就能得到更多的数据。

Divergent Change
    如果某个 class 经常因为不同的原因在不同的方向上发生变化,Divergent Change 就出现了。针对于一外界变化的所有相应修改,都只应该发生在单一class中。

Shotgun Surgery
    与Divergent Change 类似,但恰恰相反。如果每遇到某种变化,你都必须在许多不同的 class 内做出许多小修改以回应之,你嗦面临的坏味道就是Shotgun Surgery。如果需要修改的代码散布四处,你不但很能找到他们,也很容易忘记某个重要的修改。Divergent Charge 是指“一种变化引发对一个class的相应修改”。这两种情况下你都希望整理代码,取得“外界变化”与“待改类”呈现一对一关系的理想境地。

Feature Envy
    有一种经典气味是:函数对某个class的兴趣高过对自己所处之host class的兴趣。这种孺慕之情最通常的焦点便是数据。最根本的原则是:将总是一起变化的东西放在一块儿。“数据”和“引用这些数据”的行为总是一起变化的,但也有例外。如果例外出现,我们就搬移那些行为,保持“变化只在一地发生”。

Data Clumps
    数据项(data items)就像小孩子:喜欢成群结队地待在一块儿。你常常可以在很多地方看到相同的三货四笔数据项:两个classes内的相同值域(field)、许多函数签名式(signature)中的相同参数。这些“总是绑在一起出现的数据”真应该放进属于他们自己的对象中。

Primitiver Obsession
    对象的一个极具价值的东西是:它们模糊(甚至打破)了横互于基本数据和体积较大的classes之间的界限。你可以轻松编写出一些与语言内置(基本)类型无异的小型classes。你可以运用Replace Date Value with Object 将原本单独存在的数据值替换为对象,从而走出传统的洞窑,进入炙手可热的对象世界。

Switch Statements
    面向对象程序的一个最明显的特征就是:少用switch(或case)语句。从本质上说,switch语句的问题在于重复(duplication)。你经常会发现同样的switch语句散布于不同的地点。如果要为它添加一个新的case子句,你必须找到所有switch语句并修改它们。面向对象中的多态(polymorphism)概念可为此带来优雅的解决办法。

Parallel Inheritance Hierarchies
    是Shotgun Surgery的特殊情况。在这种情况下,每当你为某个class增加一个subclass,必须也为另外一个class相应增加一个subclass。

Lazy Class
    你所创建的每一个class都得有人去理解它,维护它,这些工作都是要花钱的。如果一个class的所得不值其身价,她就应该消失。

Speculative Generality
    这个令我们十分敏感的坏味道,命名者是Brian Foote。当有人说:“噢,我想我们总有一天需要做这事”并因而企图以各式各样的挂钩(hooks)和特殊情况来处理一些非必要的事情,这种坏味道就出现了。

Temporary Field
    有时你会看到这样的对象:其内某个instance 变量仅为某种特定情势而设。这样的代码让人不易理解,因为你通常认为对象所有时候都需要它的所有变量。在变量未被使用的情况下猜测当初其设置的目的,会让你疯掉。

Message Chains
    如果你看到用户向一个对象索求另一对象,然后再调用后者索求另一个对象,然后再索求另外一个对象.......采用这种方式,意味客户将与查找过程中的航行结构(structure of navigation)紧密耦合。一旦对象间的关系发生任何变化,客户端就不得不作出相应的修改。

Middle Mon
    对象的基本特征之一就是封装(encapsulation)——对外部时间隐藏其内部细节。封装往往伴随delegation。但是人们可能过度运用delegation。你也许会看到某个class接口有一半的函数都委托给其他class,这样就过度运用了。

Inappropriate Intimacy
    有时你看到两个class过于亲密,花费太多时间去探究彼此的private成分。继承(inheritance)往往造成过度亲密,因为subclass对supclass的了解总是超过supplass的主观愿望。

Inconplete Library Class
    不完美的程序库类。如果你想修改library classes内的一两个函数,可以运用Introduce Foreign Method;如果想要添加一大堆额外行为,就得运用Intrduce Local Extension。

Data Class
    它们拥有一些值域(fields),以及用于访问(读写)这些值域的函数,除此之外一无长物。这样的class只是一种“不会说话的数据容器”,它们几乎一定被其他classes过分细锁的操控着。Data Class就像小孩子,作为一个起点很好,但若要让它们像成成年的对象那样参与整个系统的工作,它们就必须承担一定责任。

Refused Bequest
    subclassed应该继承superclass的数据和函数。但如果它们不想或不需要继承,又该怎么办?按传统说法,这就意味继承体系设计错误。你需要为这个subclass新建一个兄弟(sibling class),再运用Push Down Method和Push Down Fieled 把所有用不到的函数下推给那个用兄弟。

Comments
    可以帮助我们找到先前提到的多种坏味道,找到坏味道后,我们首先应该以各种重构手法把坏味道去除。完成之后我们常常会发现:注释已经变得多余了,因为代码已经清楚说明了一切。当你感觉需要撰写注释,请先尝试重构,试着让所有注释都变得多余。如果你不知道该做什么,这才是注释的良好运用时机。除了用来记述将来的打算之外,注释还可以用来标记你并无十足把握的区域。你可以在注释里写下自己”为什么做某事“这类信息。可以帮助将来的修改者,尤其是那些健忘的家伙。
原创粉丝点击