
重构 - 代码的坏味道
IT_FISH629
纯正程序员一枚
展开
-
代码的坏味道之一 :Duplicated Code(重复的代码)
臭味行列中首当其冲的就是Duplicated Code(重复的代码)。如果你在一个以上的地点看到相同的程序结构,那么当可肯定:设法将它们合而为一,程序会变得更好。最单纯的Duplicated Code就是「同一个class内的两个函数含有相同表达式(expression)」。这时候你需要做的就是采用 提炼函数 的方法提炼出重复的代码,然后让这两个地点都调用被提炼出来的那一段代码。另一种转载 2013-05-02 11:44:08 · 4488 阅读 · 1 评论 -
代码的坏味道之二十一 :Refused Bequest(被拒绝的遗贈)
Subclasses 应该继承superclasses的函数和数据。但如果它们不想或不需要继承,又该怎么办呢?它们得到所有礼物,却只从中挑选几样来玩!按传统说法,这就意味继承体系设计错误。你需要为这个subclass 新建一个兄弟(sibling class),再运用Push Down Method(函数下移) 和 Push Down Field(值域下移)把所有用不到的函数下推给那兄转载 2013-05-03 09:32:51 · 1727 阅读 · 0 评论 -
代码的坏味道之九 :Primitive Obsession(基本型别偏执)
大多数编程环境都有两种数据:结构型别(record types)允许你将数据组织成有意义的形式;基本型别(Primitive type)则是构成结构型别的积木块。结构总是会带 来一定的额外开销。它们有点像数据库中的表格,或是那些得不偿失(只为做一两件事而创建,却付出太大额外开销〕的东西。对象的一个极具价值的东西是:它们模糊(甚至打破)了横亘于基本数据和体积较大的classes之间的界限。你转载 2013-05-02 18:15:36 · 2314 阅读 · 0 评论 -
代码的坏味道之十 :Switch Statements(switch惊悚现身)
面向对象程序的一个最明显特征就是:少用switch (或case)语句。从本质上说, switch语句的问题在于重复(duplication)。你常会发现同样的switch语句散布 于不同地点。如果要为它添加一个新的子句,你必须找到所有switch语句 并修改它们。面向对象中的多态(polymorphism )概念可为此带来优雅的解决办法。大多数时候,一看到switch语句你就应该考虑以「转载 2013-05-02 18:33:35 · 2515 阅读 · 0 评论 -
代码的坏味道之八 :Data Clumps(数据泥团)
数据项(data items)就像小孩子:喜欢成群结队地待在一块儿。你常常可以在很多地方看到相同的三或四笔数据项:两个classes内的相同值域(field)、许多函数签名式(signature)中的相同参数。这些「总是绑在一起出现的数据」真应该放进属于它们自己的对象中。首先请找出这些数据的值域形式(field)出现点,运用Extract Class(提炼类)将它们提炼到一个独立对象中。然后将转载 2013-05-02 18:04:38 · 6822 阅读 · 0 评论 -
代码的坏味道之十五 :Message Chains(过度耦合的消息链)
如果你看到用户向一个对象索求(request)另一个对象,然后再向后者索求另一个对象,然后再索求另一个对象……这就是Message Chains。实际代码中你看到的可 能是一长串getThis()或一长串临时变量。采取这种方式,意味客户将与查找过程中的航行结构(structure of the navigation)紧密耦合。一旦对象间的关系发生任何变化,客户端就不得不做出相应修改。这时候转载 2013-05-03 09:10:55 · 1824 阅读 · 0 评论 -
代码的坏味道之十八 :Alternative Classes with Different Interfaces(异曲同工的类)
如果两个函数做同一件事,却有着不同的签名式(signatures),请运用Rename Method (重新命名函数)根据它们的用途重新命名。但这往往不够,请反复运用Move Method (搬移函数)将某些行为移入classes,直到两者的协议(protocols )一致为止。如果你必须重复而赘余地移入代码才能完成这些,或许可运用Extract Superclass(提炼超类)为自己赎转载 2013-05-03 09:21:55 · 806 阅读 · 0 评论 -
代码的坏味道之二十 :Data Class(纯稚的数据类)
所谓Data Class是指:它们拥有一些值域(fields),以及用于访问(读写〕这些值域的函数,除此之外一无长物。这样的classes只是一种「不会说话的数据容器」,它们几乎一定被其他classes过份细琐地操控着。这些classes早期可能拥有public值域,果真如此你应该在别人注意到它们之前,立刻运用Encapsulate Field(封装值域)将它们封装起来。如果这些classes转载 2013-05-03 09:28:21 · 2872 阅读 · 0 评论 -
代码的坏味道之二十二 :Comments(过多的注释)
别担心,我们并不是说你不该写注释。从嗅觉上说,Comments不是一种坏味道;事实上它们还是一种香味呢。我们之所以要在这里提到Comments,因为人们常把它当作除臭剂来使用。常常会有这样的情况:你看到一段代码有着长长的注释,然后发现,这些注释之所以存在乃是因为代码很糟糕。这种情况的发生次数之多,实 在令人吃惊。Comments可以带我们找到本章先前提到的各种坏味道。找到坏味道后,我们首先转载 2013-05-03 09:36:08 · 1232 阅读 · 0 评论 -
代码的坏味道之十二 :Lazy Class(冗赘类)
你所创建的每一个class,都得有人去理解它、维护它,这些工作都是要花钱的。如 果一个class的所得不值其身价,它就应该消失。项目中经常会出现这样的情况: 某个class原本对得起自己的身价,但重构使它身形缩水,不再做那么多工作;或开发者事前规划了某些变化,并添加一个class来应付这些变化,但变化实际上没 有发生。不论上述哪一种原因,请让这个class庄严赴义吧。如果某些subclass没有做转载 2013-05-02 18:44:09 · 1003 阅读 · 0 评论 -
代码的坏味道之十九 :Incomplete Library Class(不完美的程序库类)
复用(reuse)常被视为对象的终极目的。我们认为这实在是过度估计了(我们只是使用而己)。但是无可否认,许多编程技术都建立在library classes (程序库类)的基础上,没人敢说是不是我们都把排序算法忘得一干二净了。library classes构筑者没有未卜先知的能力,我们不能因此责怪他们。毕竟我们自己也几乎总是在系统快要构筑完成的时候才能弄清楚它的设计,所以library 构筑转载 2013-05-03 09:25:24 · 1077 阅读 · 0 评论 -
代码的坏味道之十七 :Inappropriate Intimacy(狎昵关系)
有时你会看到两个classes过于亲密,花费太多时间去探究彼此的private成分。如果这发生在两个「人」之间,我们不必做卫道之士;但对于classes,我们希望它们严守清规。就像古代恋人一样,过份狎昵的classes必须拆散。你可以采用 Move Method(搬移函数) 和 Move Field(搬移值域) 帮它们划清界线,从而减少狎昵行径。你也可以看看是否运用 Change Bidi转载 2013-05-03 09:19:20 · 2308 阅读 · 0 评论 -
代码的坏味道之四 :Long Parameter List(过长参数列)
刚开始学习编程的时候,老师教我们:把函数所需的所有东西都以参数传递进去。这可以理解,因为除此之外就只能选择全局数据,而全局数据是邪恶的东西。对象 技术改变了这一情况,因为如果你手上没有你所需要的东西,总可以叫另一个对象给你。因此,有了对象,你就不必把函数需要的所有东西都以参数传递给它了,你只需传给它足够的东西、让函数能从中获得自己需要的所有东西就行了。函数需要的东西多半可以在函数的宿主类(host转载 2013-05-02 14:01:06 · 1098 阅读 · 0 评论 -
代码的坏味道之五 :Divergent Change(发散式变化)
我们希望软件能够更容易被修改——毕竟软件再怎么说本来就该是「软」的。一旦需要修改,我们希望能够跳到系统的某一点,只在该处做修改。如果不能做到这点,你就嗅出两种紧密相关的刺鼻味道中的一种了。如果某个class经常因为不同的原因在不同的方向上发生变化,Divergent Change就出现了。当你看着一个class说:『呃,如果新加入一个数据库,我必须修改这三个函数;如果新出现一种金融工具,我转载 2013-05-02 14:06:39 · 2595 阅读 · 0 评论 -
代码的坏味道之三 :Large Class(过大类)
如果想利用单一class做太多事情,其内往往就会出现太多instance变量。一旦如此,Duplicated Code(重复代码)也就接踵而至了。你可以运用Extract Class将数个变量一起提炼至新class内。提炼时应该选择class内彼此相关的变量,将它们放在一起。例如"depositAmount"和 "depositCurrency"可能应该隶属同一个class。通常如果cla转载 2013-05-02 13:40:48 · 1588 阅读 · 0 评论 -
代码的坏味道之二 :Long Method(过长函数)
拥有[短函数」(short methods)的对象会活得比较好、比较长。不熟悉面向对象技术的人,常常觉得对象程序中只有无穷无尽的delegation(委托),根本没有进行任何计算。和此类程序共同生活数年之后,你才会知道,这些小小函数有多大价值。「间接层」所能带来的全部利益——解释能力、共享能力、选择能力——都是由小型函数支持的。很久以前程序员就巳认识到:程序愈长愈难理解。早期的编程语言中,转载 2013-05-02 13:30:13 · 1190 阅读 · 0 评论 -
代码的坏味道之六 :Shotgun Surgery(散弹式修改)
Shotgun Surgery类似Divergent Change,但恰恰相反。如果每遇到某种变化,你都必须在许多不同的classes内做出许多小修改以响应之,你所面临的坏味道就是Shotgun Surgery。如果需要修改的代码散布四处,你不但很难找到它们,也很容易忘记某个重要的修改。这种情况下你应该使用Move Method(搬移函数) 和 Move Field(搬移值域)把所有需转载 2013-05-02 14:24:14 · 5043 阅读 · 0 评论 -
代码的坏味道之七 :Feature Envy(依恋情结)
对象技术的全部要点在于:这是一种「将数据和加诸其上的操作行为包装在一起」 的技术。有一种经典气味是:函数对某个class的兴趣高过对自己所处之host class的兴趣。这种孺慕之情最通常的焦点便是数据。无数次经验里,我们看到某个函数 为了计算某值,从另一个对象那儿调用几乎半打的取值函数(getting method)。疗法显而易见:把这个函数移至另一个地点。你应该使用Move Method(转载 2013-05-02 17:55:12 · 5959 阅读 · 0 评论 -
代码的坏味道之十一 :Parallel Inheritance Hierarchies(平行继承体系)
Parallel Inheritance Hierarchies其实是shotgun surgery的特殊情况。在这种情况下,每当你为某个class增加一个subclass,必须也为另一个class相应增加一个subclass。如果你发现某个继承体系的名称前缀和另一个继承体系的名称前缀完全相同,便是闻到了这种坏味道。消除这种重复性的一般策略是:让一个继承体系的实体(instance)指涉(转载 2013-05-02 18:38:26 · 1535 阅读 · 0 评论 -
代码的坏味道之十三 :Speculative Generality(夸夸其谈未来性)
这个令我们十分敏感的坏味道,命名者是Brian Foote。当有人说『噢,我想我们总有一天需要做这事』并因而企图以各式各样的挂勾(hooks)和特殊情况来处理一 些非必要的事情,这种坏味道就出现了。那么做的结果往往造成系统更难理解和维护。如果所有装置都会被用到,那就值得那么做;如果用不到,就不值得。用不上的装置只会挡你的路,所以,把它搬开吧。如果你的某个abstract class其实没有转载 2013-05-02 18:48:50 · 1564 阅读 · 1 评论 -
代码的坏味道之十六 :Middle Man(中间转手人)
对象的基本特征之一就是封装(encapsulation)——对外部世界隐藏其内部细节。封装往往伴随delegation (委托)。比如说你问主管是否有时间参加一个会议,他就把这个消息委托给他的记事簿,然后才能回答你。很好,你没必要知道这位主管到底使用传统记事簿或电子记事簿抑或秘书来记录自己的约会。但是人们可能过度运用delegation。你也许会看到某个class接口有一半的函数都委托给其转载 2013-05-03 09:14:06 · 1514 阅读 · 1 评论 -
代码的坏味道之十四 :Temporary Field(令人迷惑的暂时值域)
有时你会看到这样的对象:其内某个instance变量仅为某种特定情势而设。这样的代码让人不易理解,因为你通常认为对象在所有时候都需要它的所有变量。在变量未被使用的情况下猜测当初其设置目的,会让你发疯。请使用 Extract Class(提炼类) 给这个可怜的孤儿创造一个家,然后把所有和这个变 量相关的代码都放进这个新家。也许你还可以使用 Introduce Null Object(引入Nu转载 2013-05-03 09:02:48 · 1131 阅读 · 0 评论