代码的坏味道

《重构》第三章学习笔记

我们必须培养自己的判断力,来决定在什么时候进行重构。

1.1  Duplicate Code(重复代码)

如果你在一个以上地点看到相同的程序结构,那么将他们合而为一会更好。

1.2  Long Method(过长函数)

拥有短函数的对象会活得比较好,比较长。

间接层所能带来的全部益处:解释能力(可读性),共享能力(重用性),选择能力(?)。

现在OO 语言基本解决了函数调用所产生的开销。

“ 你应该更积极进去的分解函数。我们遵循这样一条原则:每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个函数中,并以其用途(而非实现手法)命名。我们可以对一组甚至短短一行代码(拥有复杂逻辑,难以理解)做这件事。哪怕替换后的函数调用动作比函数自身还长,只要函数名称能够解释其用途,我们也该毫不犹豫的这么做。关键不在于函数的长度,而在于“做什么”和“如何做”之间的语义距离。 ”

“如何确定该提炼哪一段代码?一个很好的技巧是:寻找注释。它们通常是指出“代码用途和实现手法间的语义距离”的信号。如果代码需要用注释来说明其用途,那么就要考虑把这段代码提炼成独立的函数,并且用注释来为此函数命名。”

复杂条件式和循环液常常是提炼的信号。

1.3  Large Class(过大类)

如果想利用单一的class 做太多的事情,其内往往会出现太多的 instance 变量。

如果class 中拥有太多的代码,也是“代码重复、混乱、死亡”的绝佳滋生点。

1.4  Long Parameter List(过长的参数列表)

过长的产生导致程序难以理解。

1.5  Divergent Change(发散式变化)

“ 一个class 受多个外界变化的影响 ”,则把这多个变化封装成一个新的类。即“ 将总是一起变化的东西放在一起 ”

针对外界某一变化所有相应的修改,都应该只发生在单一的class 中,而这个 class 的所有内容都应该反映该外界变化。总的思想就是,封装变化。这个地方和设计模式的想法是一致的。

1.6  Shotgun Surgery(散弹式修改)

和发散式变化不同,每次遇到变化,都要在多个class 中进行小的修改以响应之。他们分散在多处,很容易出错。

这里的主要思想是集中变化。

散弹式修改指的是,“ 一种变化引发多个class 的修改 ”,发散式变化指的是“ 一个class 受多个外界变化的影响 ”。

这两种情况下,通过重构, 使“外界变化”和“待修改类”呈一对一关系 的理想境地。

1.7  Feature Envy(依恋情节)

某个函数对其他类的数据的兴趣,高过对host class 的兴趣。即对其他的类的数据的依赖十分大。

1.8  Data Clumps(数据泥团)

数据泥团指的是总是绑定在一起出现的数据。

一个好的评断方法:删除众多数据中的一项数据,其他数据是否是因而失去了意义?如果他们不再有意义:你应该为他们产生一个新的对象。

形成新的对象后,可以根据Feature Envy 将一些操作移至此对象中。

1.9  Primitive Obsession(基本型别偏执)

建立多个很小,但是很灵活的对象。

1.10  Switch Statements( switch 惊悚现身)

使用面向对象编程,要少用switch 和 case 语句。而是用多态来替换它。

1.11  Parallel Inheritance Hierarchies(平行继承体系)

每当你为一个class 增加一个 subclass 的时候,必须为另一个 class 增加一个 subclass 。一般这两个 class 的前缀相同。

1.12  Lazy Class(冗赘类)

类显得多余,没有价值。

1.13  Speculative Generality(夸夸其谈未来性)

这个往往是过度设计的结果:对某种变化的应对,而这种变化没有发生。

1.14  Temporary Field(令人迷惑的暂时值域)

变量只在特定的情形下有效,而并不是所有的情况下有效。很多情况下,这些值域应该不属于此class ,而应该单独的提取成新的类。

1.15  Message Chains(过度耦合的消息链)

用户向一个对象索取另一个对象,然后在向后者索求另一个对象,然后在索求另一个对象——客户与查找过程的航行结构紧密耦合。

1.16  Middle Man(中间转手人)

对象的基本特征之一就是封装——对外部世界隐藏实现细节——封装往往伴随委托。委托的过度运行,就导致了Middle Man 。

1.17  Inappropriate Intimacy (亲密关系)

两个class 之间的关系过于亲密。比如,花大量的时间探究彼此的 private 成分。

1.18  Alternative Classes with Different Interface(异曲同工的类)

类名不同,但是功能相似。

1.19  Incomplete Library Class(不完美的程序类库)

基础类库无法满足实际的需求。

1.20  Data Class(纯稚的数据类)

它们拥有一些值域,以及用于访问(读写)这些值域的函数,除此之外一无长物。

1.21  Refused Bequest(被拒绝的遗赠)

子类不像继承父类的函数和数据,这往往是继承体系的错误。

如果子类复用父类的行为,但又不愿支持父类的接口,这种情况下Refused Bequest 的坏味道会很强烈。

1.22  Comments(过多的注释)

注释其实是一种香味,更多的情况下它被用作除臭剂:即代码中出现坏味道(设计糟糕的代码),然后用注释“除臭”。这个时候我们应该对这些坏味道的代码进行重构,然后,你会发现注释变成了多余的。

当你感觉需要注释,请先尝试重构,试着让所有的注释都变得多余——代码本身就是自注释的。

注释可以用来记述“为什么做某事”、“打算做某事”、“无十足把握的区域”,而不必记录“怎么做”。

posted @ 2009-10-12 20:15  常高伟  阅读(692)  评论(0编辑  收藏  举报