《重构》阅读笔记-代码的坏味道

决定何时重构、何时停止和知道如何重构一样重要!

开发者必须通过实践培养自己的经验和直觉,培养出自己的判断力:学会判断一个类内有多少个实例变量算是太大、学会判断一个函数内有多少行代码才算太长。

  1. 重复代码(Duplicated Code)
    如果你在一个以上的地方看到相同的程序结构,那么可以肯定:设法将它们合而为一,程序会变得更美好!你需要决定这个重复的代码放在哪里比较合适,并确保它被安置之后就不会在别的地方再次出现。

  2. 过长函数(Long Method)
    程序越长越难以理解。现代OO语言几乎完全免去了进程内的函数调用开销,因此,你应该积极地分解函数。我们应该遵循原则:每当需要以注释来说明点什么的时候,我们就需要把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。如何确定需要提炼哪一段代码:寻找注释、条件表达式、循环。

  3. 过大的类(Large Class)
    如果你发现一个类试图做太多事情,其内部就会出现很多不相关的实例变量,此时这个类的职责就不明确了。

  4. 过长参数列(Long Parameter List)
    太长的参数队列难以理解,太多参数的接口对于使用者来说十分不友好,而且容易出错。如果可以使用一个对象代替参数列表,那么就应该这么做。

  5. 发散式变化(Divergent Change) VS 霰弹式修改(Shotgun Surgery)
    一旦需要修改,我们希望只在系统的一个地方进行修改,否则,就属于两种非常相似的坏味道的一种:如果某个类经常因为不同的原因在不同的地方发生变化,那么Divergent Change就出现了;如果系统每遇到一个小变化,就需要在多个不同的类内进行许多小修改,这属于Shotgun Surgery。Divergent Change是指“一个类受多种变化的影响”,Shotgun Surgery则指的是“一种变化引发多个类的修改”。

  6. 平行继承体系(Parallel Inheritance Hierarchies)
    这其实是Shotgun Surgery的特殊情况——每当你为某个类添加一个子类,你也必须为它的兄弟类加一个子类。如果你发现某个继承体系的类名称前缀和另一个继承体系的类名称前缀完全相同,就属于这种情况。

  7. 依恋情结(Feature Envy)
    面向对象的精髓在于:“将数据和对数据的操作行为包装在一起”。有一种气味是:函数对某个类的兴趣高过自己所处的类的兴趣。有很多时候,我们看到一个函数为了计算某个值,从另一个对象那儿调用了几乎半打的取值函数。最根本的原则是:将总是一起变化的东西放在一起。

  8. 数据泥团(Data Clumps)
    你常常可以在很多地方看到相同的三四项数据:两个类中相同的字段、许多函数签名中相同的参数。这些绑在一起出现的数据真应该拥有属于它们自己的对象。减少字段和参数的个数,当然可以去除一些坏味道,但更重要的是:一旦拥有新对象,你就有机会寻找Feature Envy,这可以帮你指出能够移至新类中的种种方法

  9. 基本类型偏执(Primitive Obsession)
    对象技术的新手通常不愿意在小任务上运用对象——例如结合数值和币种的Money类、由一个起始值和一个结束值构成的Range类、电话号码或邮政号码等的特殊字符串。

  10. switch语句(Switch Statements)
    从本质上讲,switch语句的问题在于重复,面向对象的多态特性可以优雅地解决这个问题。如果你只是在单一函数内有些选择事例,那么用多态就属于杀鸡用牛刀了,这种情况下Replace Parameter with Explicit Methods是个不错的选择,如果你的选择之一是null,记得使用Introduce Null Object。

  11. 多余的类(Lazy Class)
    你所创建的每一个类,都得有人去理解它、维护它,这些工作都是要花钱的。如果一个类的所得不值得其身价,就应该消除这个类。

  12. 过度设计(Speculative Generality)
    当有人说“噢,我想我们有一天需要做这个事情”,并因此而企图以各种各样的钩子和特殊情况来处理一些非必要的事情,这种坏味道就出现了。软件设计不可过度设计,否则会使得系统难以理解和维护。

  13. 令人迷惑的暂时字段(Temporary Field)
    有时你会看到这样的现象:类内的某个实例变量仅为某种特定情况而设。这样的代码不易理解,因为通常认为对象在所有时候都需要它的所有变量。

  14. 过度耦合的消息链(Message Chains)
    如果你看到用户向一个对象请求另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象……这就是消息链。实际代码中你看到的可能是一长串getXXX()调用,意味着客户代码将与查找目标对象过程中的导航结构紧密耦合,一旦对象间的关系发生任何变化,客户端就会受到影响。

  15. 中间人(Middle Man)
    对象的基本特征之一是封装——对外部世界隐藏其内部细节。封装往往伴随着委托,比如你问主管是否有时间参加一个会议,他就把这个消息“委托”给他的记事簿,然后才能回答你——你没有必要这位主管到底是使用传统记事簿或电子记事簿或秘书来记录自己的约会。但是,不要过度使用委托——你也许会看到某个类有一半接口都委托给其他类。

  16. 狎昵关系(Inappropriate Intimacy)
    类与类之间过分紧密的关系必须拆散——可以引入第三方类或者利用委托。

  17. 异曲同工的类(Alternative Classes with Different Interfaces)
    如果两个函数做同一件事,却有着不同的签名,请运用Rename Method根据它们的用途重新命名。但这往往不够,请反复运用Move Method将某些行为移入类,知道这两个函数的协议一致为止。如果你必须移动大量代码才可以完成这个工作,那还不如直接构建一个父类。

  18. 不完美的库类(Incomplete Library Class)
    复用常常被认为是面向对象技术的终极目标。很多第三方库提供的接口经常不能恰如其分得满足我们的需求,这时候就需要对第三方接口做一层转换,或者给它添加一定的行为。

  19. 数据类(Data Class)
    所谓Data Class,指的是:这种类拥有一些字段,以及用于访问(读、写)的函数,除此之外啥都没有。这样的类只是一种不会说话的数据容器,它们一定被其他类过分细碎得控制着。
    Data Class就像小孩子,作为一个起点很好,但若要让它们像成熟的对象那样参与整个系统的工作,它们就必须承担一定责任。但是,在Spring框架开发中,我们经常需要定义很多domain对象。

  20. 被拒绝的遗嘱(Refused Request)
    子类应该继承超类的函数和数据,但如果它们不想或者不需要继承,又该怎么办呢?按照传统说法,这就意味着继承体系的设计错误。你需要为这个子类新建一个兄弟类,然后让父类只包括两个子类共享的部分。
    一般而言,这就足够了,但是如果子类不愿意支持超类提供的接口,则说明不能使用继承处理,应该使用委托。

  21. 过多的注释(Comments)
    常常会有这样的情况:你看到一段代码有着长长的注释,然后发现,这些注释之所以存在乃是因为代码很糟糕。当你需要些注释时,要先尝试重构下代码,争取让代码拥有自说明性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,846评论 2 374
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,146评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,789评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,656评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,467评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,870评论 3 389
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,500评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,790评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,828评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,628评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,449评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,881评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,077评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,376评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,879评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,089评论 2 338

推荐阅读更多精彩内容