「重构」读书笔记

重构不是目的,而是工具。

为何重构

改进软件设计
  • 维持或改进代码的设计意图,避免代码结构流失
  • 消除重复代码,方便未来的修改
使软件更容易理解
  • 让代码准确说出你所要的
  • 让别人能很快看懂你写的
  • 让代码凸显你的设计意图
提高编程速度
  • 良好设计帮助你快速开发

何时重构

重构应该随时随地进行,但不应该为重构而重构

准则:事不过三,三则重构

添加功能时重构

当代码的设计无法轻松添加需要的特性时,用重构来改善设计,让未来增加新特性时能够更轻松一些

调试过程中重构

良好的设计能更容易找出有问题的代码,调试时,运用重构使代码更清晰

复审代码时重构

代码复审能提高编程能力,传播知识,编写清晰的代码

在复审时,考虑是否可以通过重构轻松实现

代码的坏味道

Duplicated Code(重复代码)
  • 同个类的两个函数含有相同的表达式
  • 两个互为兄弟的子类内含有相同的表达式
  • 两个毫不相关的类出现重复的代码
Long Method(过长函数)

程序越长越难理解

分解成小型函数,更好的解释其用途

寻找注释,把需要说明的东西写进一个独立函数中,并以其用途命名

Large Class(过大的类)

类中如果有太多代码,会变得混乱

可以通过提炼类、提炼子类或提炼接口来分解

Long Parameter List(过长参数列)

太长的参数列难以理解,太多参数会造成前后不一致、不易使用

考虑参数能否由方法代替,能否通过传递一个对象获取一些参数,能否构造一个参数对象

Divergent Change(发散式变化)

一个类受多种变化的影响

针对某一外界变化的所有相应修改,都只应该发生在单一类中

应该找出某特定原因而造成的所有变化,然后将它们提炼到另一个类中,这个新类内的所有内容都应该反应此变化

Shotgun Surgery(霰弹式修改)

一种变化引发多个类相应修改

每遇到某种变化,都必须在许多不同的类内做出许多小修改

应该把所有需要修改的代码放进同一个类

Feature Envy(依恋情结)

函数对某个类的依赖高于本身所在的类

应该把函数移至它该去的地方

原则是:判断哪个类拥有最多被此函数使用的数据,然后就把这个函数和那些数据摆在一起

Data Clumps(数据泥团)

相同的几项数据同时出现在类中或参数列中

如果这些数据之间存在联系,删除其中一项会使其它数据失去意义,那么需要为它们产生一个新对象

Primitive Obsession(基本类型偏执)

多个基本类型的数据存在一定的联系,应该被放在一起

创建新的对象,将它们组织起来

Switch Statements(Switch声明)

switch语句的问题在于重复

一看到switch语句,就应该考虑以多态来替换它

先将switch语句提炼到一个独立函数,再将它搬移到需要多态性的那个类里

Parallel Inheritance Hierarchies(平行继承体系)

每当为某个类增加一个子类,必须也为另一个类相应增加一个子类

这时,应该让一个继承体系的实例引用另一个继承体系的实例

Lazy Class(冗赘类)

类没有存在意义或意义不大

代表月亮消灭它

Speculative Generality(夸夸其谈未来性)

假设未来某天会用到,创建不必要的类和方法

如果用不到,就果断的舍弃它

Temporary Field(令人迷惑的暂时字段)

某个实例变量仅为某种特定情况而设

创建一个新类,将这个变量和相关代码都放进这个类中

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

向一个对象请求另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象...

对象间的结构紧密耦合,一旦对象间的关系发生任何变化,则调用端不得不做出相应修改

这时,应该在服务类建立所需的所有函数,用以隐藏委托关系

Middle Man(中间人)

随着受托类的特性越来越多,服务类完全变成了一个「中间人」

这时,应该暴露受托类,让客户直接调用受托类

Inappropriate Intimacy(狎昵关系)

两个类过于亲密

不同的类应保持独立

如果两者有共同点,则提炼到一个新类,让它们共同使用;如果子类的行为已不符合父类的意图,则考虑让子类离开继承体系

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

两个函数做同一件事,却有着不同的签名

应该根据它们的用途重新命名

Incomplete Library Class(不完美的库类)

现有的库类无法满足需求

可以选择引入外部方法或者继承该类扩展库类

Data Class(纯稚的数据类)

如果一个类只是单纯的读写字段,就让它做一个数据类,封装字段,向外提供读写方法

Refused Bequest(被拒绝的馈赠)

如果子类不需要父类的函数和数据,意味着继承体系设计错误

这时,应该新建一个兄弟类,让父类只持有所有子类共享的东西

如果子类复用了父类的行为,却不支持父类的接口,可以使用委托来达到目的

Comments(过多的注释)

长长的代码用注释说明意图

如果需要注释来解释一块代码做了什么,试试提炼成函数,用函数名解释其行为

常用重构手法

提炼方法

过长的函数不易理解,考虑把一段代码提炼出来,放进一个单独的函数中,并以其用途命名函数

以查询取代临时变量

如果多个方法中出现相同的临时变量,考虑是否能以函数替代

引入解释性变量

如果一个表达式过于复杂而难以阅读(常见于条件语句)

考虑将该表达式或其中一部分的结果放进一个临时变量,以此变量名称来解释表达式用途

如果该表达式有多处引用,则可以考虑将表达式提炼成方法

移除对参数的赋值

在Java中,不要对参数赋值

替换算法

将函数本体替换为另一个算法,使之更清晰易读

提炼类

一个类应该是一个清楚的抽象,处理一些明确的责任

如果某个类做了应该由两个类做的事,考虑提炼出一个新类

隐藏委托

如果某个对象不需要暴露给客户,考虑在服务类建立客户所需的所有函数,隐藏委托关系,由服务类调用所需对象

引入外加函数

为无法修改的类增加函数

引入本地扩展

继承一个无法修改的类,并增加函数

自封装字段

为字段建立取值和设值函数,并且只以这些函数来访问字段

以对象取代数据值

新建一个数据类,取代简单类型的变量

以对象取代数组

如果有一个数组,其中的元素各自代表不同的东西,考虑新建一个类,数组中的每个元素,以一个字段来表示

复制被观察的数据

常见于服务类和界面类的数据交互,考虑建立一个 Observer 模式,用以同步服务类和界面类的重复数据

以字面常量取代数值

如果在代码中有特别含义的字面数值,应定义为常量再使用

以类取代类型码

当遇到一组数值类型码,该类型码不会影响宿主类的行为时,可考虑新建一个类来替换该类型码

以子类取代类型码

当类型码会影响宿主类的行为时,考虑借助多态来处理

以 State模式 / Strategy模式 取代类型码

当类型码会影响宿主类的行为,而无法通过继承时,考虑用状态对象取代类型码

以卫语句取代嵌套条件表达式

如果某个条件极其罕见,就应该单独检查该条件,并在该条件为真时立即从函数中返回,这样的单独检查常常被称为 卫语句

以多态取代条件表达式

假设当前有个条件表达式,它根据对象类型的不同而选择不同的行为

考虑通过多态,创建不同的子类来替代

引入空对象

若需要再三检查某对象是否为 null ,可创建一个空对象来处理

保持对象完整

将传递某对象的若干值,改为传递整个对象

引入参数对象

若某些参数总是同时出现,考虑以一个对象取代这些参数

提炼子类

若类中的某些特性只被某些实例用到,考虑新建一个子类,将该部分特性移到子类中

提炼超类

若两个类有相似特性,考虑为这两个类创建一个超类,将相同特性移到超类

提炼接口

将相同的子集提炼到一个独立接口中

以委托取代继承

若某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据

考虑在子类中新建一个字段用以保存超类,调整子类函数,改而委托超类,去掉继承关系

以继承取代委托

如果需要使用受托类中的所有函数,可以考虑是否能用回继承

拓展

间接层

计算机科学是这样一门科学:它相信所有问题都可以通过增加一个间接层来解决。 —— Dennis DeBruler

价值

  • 允许逻辑共享
  • 分开解释意图和实现
  • 隔离变化
  • 封装条件逻辑
不可变的值对象

不可变指的是对象本身不可变,如果要改变对象,需要使用另一个对象来取代现有的对象,而不是在现有对象上修改。类似 String

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

推荐阅读更多精彩内容