《以下内容来自《重构—改善既出代码的宏图》

重构——改善既来代码的计划性
Refactoring——Improve the Design of Existing Code
作者: 马丁 富勒Martin Fowler

重构手法


代码的坏味道

同等、什么是重构?

所谓重构大凡这样一个过程在非移代码外在表现之前提下,对代码作出修改,以精益求精程序的内部结构。本质上说,重构就是以代码写好以后改进其的统筹

重构(名词):对软件内部结构的如出一辙栽调整,目的是以非改变软件可观察行为之前提下,提高该可理解性,降低其修改成本
重构(动词):采用同样密密麻麻重构手法,在不转软件而察行为之前提下,调整其结构

重构的目的是要软件再易于为了解和修改。重构无见面变动软件可观察的行——重构之后软件功能依然。

重构技术就是盖一线的步伐修改程序,如果您犯下错,很容易就足以窥见她。


以下内容来自《重构—改善既来代码的宏图》

次、为何重构?

(1)
重构改进软件设计。如果没有重构,程序的规划会日益堕落变质。重构很像是于整代码,你所召开的就是是让所有东西回到应出的岗位及。经常性的重构可以扶持维持好该有的造型。

(2)重构使软件再爱懂。重构可以拉我们深受代码更易于读。

(3)重构帮助找到bug。对代码进行重构,可以扶持我们深刻了解代码,对代码理解的愈发怪,就逾会帮忙咱找到bug。重构能够助咱再使得地勾画有健康的代码。

(4)重构提高成为速度。重构可以帮忙我们还高速地开发软件,因为它阻挡系统腐败变质,它甚至还得提高统筹质量。


 

其三、何时重构?

重构不是一致码理当特别扭出时开的作业,重构应该随时随地进行。不应也重构而重构,之所以重构,是因我们怀念做别的啊事,而重构可以拉我们把那些从开好。

其三破法虽:业不了三,三虽然重构

(1)添加意义时重构。
(2)修补错误时重构。
(3)复审代码时重构。


一样、重新组织函数

季、何时休欠重构?

代码根本无法工作或者极端不好,重构还非设重复写来的简要

以项目之尾声时限,应该避免重构


1、Extract Method (提炼函数)

五、代码的坏味道

  • 双重代码(Duplicated Code)
  • 过长函数(Long Method)
  • 过大的切近(Large Class)
  • 过长参数列(Long Parameter List)
  • 发散式变化(Divergent Change):一个类受多种变通的影响
  • 霰弹式修改(Shotgun Surgery):一种变更引发多只类似对应修改
  • 留恋情结(Feature Envy):函数对某类的兴味高过好所处类的志趣
  • 数码泥团(Data
    Clumps):相同之多件数据出现在不同地方,这些绑在协同出现的多寡应生出属于它们自己之对象
  • 核心项目偏执(Private
    Obsession):很多总人口非情愿在有些任务上运小目标
  • switch惊悚现身(Switch
    Statements):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)

2、Inline Method (内联函数)

六、构筑测试系统

  1. 重构的重中之重前提是享有一个可靠的测试环境
  2. 如写好一些职能,就这添加测试,并保管有测试都完全自动化,让她检查好的测试结果。一拟测试就是一个强劲的bug侦测器,能够大大减少查找bug所要之时刻。
  3. 编写测试代码的不过可行时机是以起编程之前。当你用添加特性的上,先勾勒相应测试代码。编写测试代码其实就是于咨询自己:添加这个功能要开些什么。编写测试代码还会使您拿注意力集中让接口而无实现。预先写好之测试代码也也您的行事设置一个明明的扫尾标志:一旦测试代码正常运转,工作就足以了结了。
  4. 大抵应用单元测试。测试你无比放心不下失误的地方,考虑或者出错的边界条件。不要为测试无法捕捉所有bug就未写测试,因为测试的确可以捕捉到大多数bug。“花合理时间抓来大多数bug”要好了“穷尽一生抓来具有bug”。

3、Inline Temp
(内联临时变量)

七、重新组织函数

  1. 提炼函数(Extract
    Method)。你发平等截代码可以叫组织在一起并独自出来。将即时段代码放上一个独门函数中,并将函数名称解释该函数的用处。
  2. 内联函数(Inline
    Method)。一个函数的本体和名一致清楚易亮。在函数调用点插入函数本体,然后变除该函数。
  3. 内联临时变量(Inline
    Temp)。你生一个临时变量,只给一个简单易行表达式赋值一糟,而它妨碍了外重构手法。将拥有对拖欠变量的援动作,替换为对它们赋值的雅表达式自身。
  4. 坐询问取代临时变量(Replace Temp with
    Query)。你的次因一个即变量保存有一样表达式的演算结果。将之表达式提炼到一个单身函数中。将以此临时变量的具备引用点替换为对新函数的调用。此后,新函数就可为另外函数使用。
  5. 引入解释性变量(Introduce Explaining
    Variable)。你有一个苛的表达式。将欠复杂表达式(或中有些)的结果放上一个即变量,以此变量名称来分解表达式用途。
  6. 诠释临时变量(Split Temporary
    Variable)。你的次序来有临时变量被赋值过一样蹩脚,它既是无是循环变量,也未为用来收集计算结果。针对每次赋值,创造一个独门、对应之旋变量。
  7. 移除对参数的赋值(Remove Assignments
    Parameters)。代码对一个参数进行赋值。以一个现变量取代参数的岗位。
  8. 盖函数对象取代函数(Replace Method with Method
    Object)。你发出一个大型函数,其中对有的变量的以如你无法用Extract
    Method。将这函数放上一个单独对象中,如此一来局部变量就成了对象内之字段。然后您得当与一个目标被以以此特大型函数分解为多单小型函数。
  9. 替换算法(Substitute
    Algorithm)。你想使管某某算法替换为任何一个还清晰的算法。将函数本体替换为其它一个算法。

4、Replace Temp with Query
(以询问取代临时变量)

八、在靶之间搬移特性

  1. 搬移函数(Move
    Method)。你的次第中,有个函数和该所驻之外的其他一个像样进行重新多交流:调用后者,或被继承人调用。在拖欠函数最常引用的切近吃起一个有所相仿表现之初函数。将原来函数变成一个一味的嘱托函数,或是将原有函数完全移除。
  2. 搬迁移字段(Move
    Field)。你的主次中,某个字段被该所驻类之外的别样一个类更多地用到。在对象类新建一个字段,修改来自字段的富有用户,令它改用新字段。
  3. 提炼类(Extract
    Class)。某只像样做了应该有零星单近乎做的事。建立一个新类,将相关的字段和函数从旧类搬移到新类。
  4. 将类似内联化(Inline
    Class)。某个类没有开尽多工作。将这看似的所有特性搬移到其他一个好像中,然后移除原类。
  5. 暗藏“委托关系”(Hide
    Delegate)。客户通过一个寄来调用另一个目标。在劳务类及树立客户所用的有着函数,用以隐藏委托关系。
  6. 移除中间人(Remove Middle
    Man)。某只八九不离十做了了多之概括委托动作。让客户直接调用受托类。
  7. 引入外加函数(Introduce Foreign
    Method)。你要吗提供劳动的近乎增加一个函数,但您无法修改是类似。在客户类中起一个函数,并坐率先参数形式传播一个服务类实例。
  8. 引入本地扩展(Introduce Local
    Extension)。你待吗服务类提供一些外加函数,但你无法修改是类似。建立一个新类,使它们涵盖这些额外函数。让这扩展品成为源类的子类或包装类。

5、Introduce Explaining
Variable
(引入解释性变量)

九、重新组织数量

  1. 由封装字段(Self Encapsulate
    Field)。你一直看一个字段,但同字段之间的耦合关系日益变得笨拙。为这字段建立取值/设值函数,并且就为这些函数来走访字段。
  2. 以目标取代数据值(Replace Data Value with
    Object)。你生一个数目项,需要和另外数据与作为同利用才有含义。将数据项改成对象。
  3. 将价值对象改吗援对象(Change Value to
    Reference)。你打一个接近衍生出许多相互相当的实例,希望将它替换为同一个对象。将是价对象变成引用对象。
  4. 将引用对象改也价值对象(Change Reference to
    Value)。你出一个引用对象,很粗且不可变,而且对管理。将它们化一个价对象。
  5. 坐目标取代数据(Replace Array with
    Object)。你闹一个反复组,其中的因素分别代表不同之事物。以目标替换数组,对于数组中的每个元素,以一个字段来代表。
  6. 复制“被监视数据”(Duplicate Observed
    Data)。你生一部分领域数据在GUI控件被,而世界函数需要看这些数据。将拖欠多少复制到一个领域对象被。建立一个Observe模式,用以同步领域对象与GUI对象内的再次数据。
  7. 用只有为关系改也双向关联(Change Unidirectional Association to
    Bidirectional)。两个像样都急需动用对方特性,但中间只来相同长就为链接。添加一个反向指针,并要修改函数能够同时创新两条链接。
  8. 将双向关联改吗单为关系(Change Bidirectional Association to
    Unidirectional)。两单类似里时有发生双向关联,但其中一个类似如今不再用另外一个好像的特色。去除不必要的涉嫌。
  9. 盖字面常量取代魔法数(Replace Magic Number with Symbolic
    Constant)。你生出一个字面数价值,带有特别意义。创造一个常量,根据其意义吗她取名,并将上述的字面数值替换为这个常量。
  10. 封装字段(Encapsulate
    Field)。你的接近中是一个public字段。将她声明也private,并提供相应的造访函数。
  11. 装进集合(Encapsulate
    Collection)。有个函数返回一个聚集。让这个函数返回该集的一个就读副本,并在这近乎中提供丰富/移除集合元素的函数。
  12. 因为数据类取代记录(Replace Record with Data
    Class)。你需要对传统编程环境中之笔录组织。为该记录创建一个“哑”数据对象。
  13. 盖看似取代类型码(Replace Type Code with
    Class)。类中产生一个数值类行码,但其并无影响类的所作所为。以一个新的类替换该数值类型码。
  14. 盖子类取代类型码(Replace Type Code with
    Subclass)。你同时一个不可变的类型码,它见面影响类的表现。以子类取代这个类型码。
  15. 以State/Strategy取代类型码(Replace Type Code with
    State/Strategy)。你发一个类型码,它见面影响类的作为,但您无法透过连续手法消除其。以状态对象取代类型码。
  16. 坐字段取代子类(Replace Subclass with
    Fields)。你的顺序子类的绝无仅有差别就以“返回常量数据”的函数身上。修改这些函数,使他么返回超类中的某部(新增)字段,然后销毁子类。

6、Split Temporary Variable
(分解临时变量)

十、简化条件表达式

  1. 解说条件表达式(Decompose
    Conditional)。你来一个犬牙交错的规范(if-then-else)语句。从if、then、else三区划段落中分别提炼出单身函数。
  2. 统一条件表达式(Consolidate Conditional
    Expression)。你生同样层层标准测试,都落一致结果。将这些测试合并为一个法表达式,并以这个规则表达式提炼成为一个单独函数。
  3. 集合重复的标准有(Consolidate Duplicate Conditional
    Fragments)。在规则表达式的每个分支上保有一样的同样段落代码。将即时段更的代码搬移到规则表达式之外。
  4. 移除控制标记(Remove Control
    Flag)。在平密密麻麻布尔表达式中,某个变量带有“控制标记”的意图。以break语句或return语句子取代控制标记。
  5. 为卫语词取代嵌套条件表达式(Replace nested Conditional with
    Guard
    Clauses)。函数中的条件逻辑使人头为难判断正常的行路径。使用卫语句表现抱有的独特状况。
  6. 以多态取代条件表达式(Replace Conditional with
    Polymorphism)。你眼前有个尺码表达式,它根据目标类型的两样选项不同之行事。将是极表达式的每个分支放上一个子类内之覆写函数中,然后用原始函数声明也架空函数。
  7. 引入Null对象(Introduce Null
    Object)。你用数检查有目标是否也null。将null值替换为null对象。
  8. 引入断言(Introduce
    Assertion)。某同截代码需要针对先后状态做出某种假设。以断言明确表现这种假设。

7、Remove Assignments to
Parameters
(移除对参数的赋值)

十一、简化函数调用

  1. 函数改名(Rename
    Method)。函数的称号不能揭示函数的用途。修改函数的称呼。
  2. 长参数(Add
    Parameter)。某个函数需要由调用端得到重新多信息。为夫函数添加一个对象参数,让该目标带来上函数所要信息。
  3. 移除参数(Remove
    Parameter)。函数本体不再需要某个参数。将该参数去除。
  4. 用查询函数和修改函数分离(Separate Query from
    Modifier)。某个函数既归对象状态值,又改对象状态。建立两独不等的函数,其中一个顶住查询,另一个担负修改。
  5. 使函数携带参数(Parameterize
    Method)。若干函数做了类似的劳作,但每当函数本体中却涵盖了不同的价值。建立单一函数,以参数表达那些不同的值。
  6. 为鲜明函数取代参数(Replace Parameter with Explicit
    Methods)。你有一个函数,其中完全在于参数值而动两样行为。针对该参数的诸一个也许价值,建立一个独函数。
  7. 保障对象完整(Preserve Whole
    Object)。你自某个对象吃取出若干价,将它们作为有平次等函数调用时的参数。改呢传送整个对象。
  8. 坐函数取代参数(Replace Parameter with
    Methods)。对象调用某个函数,并将所得结果作参数,传递给任何一个函数。而接受该参数的函数本身也能调用前一个函数。让参数接受者去除该项参数,并一直调用前一个函数。
  9. 引入参数对象(Introduce Parameter
    Object)。某些参数总是特别当然地以起。以一个靶取代这些参数。
  10. 移除设值函数(Remove Setting
    Method)。类吃的某某字段应该以对象创建时受设值,然后就不再改变。去丢该字段的兼具设值函数。
  11. 隐藏函数(Hide
    Method)。有一个函数,从来不曾吃别任何类用到。将是函数修改为private。
  12. 坐工厂函数取代构造函数(Replace Constructor with Factory
    Method)。你期望于创建对象时不只是开简单的构建动作。将构建函数替换为工厂函数。
  13. 卷入向下转型(Encapsulate
    Downcast)。某个函数返回的目标,需要由函数调用者履于下转型。将为下转型动作变到函数中。
  14. 坐稀取代错误码(Replace Error Code with
    Exception)。某个函数返回一个一定的代码,用以代表某种错误情况。改用异常。
  15. 以测试取代异常(Replace Exception with
    Test)。面对一个调用者可以先检查的极,你扔来了一个格外。修改调用者,使它在调用函数之前先举行检查。

8、Replace Method with
Method Object
(以函数对象取代函数)

十二、处理包括关系

  1. 字段上更换(Pull Up
    Field)。两独子类拥有一致的字段。将欠字段移至超类。
  2. 函数上更换(Pull Up
    Method)。有些函数,在相继子类中发生完全相同的结果。将该函数易至超类。
  3. 构造函数本体上更换(Pull Up Constructor
    Body)。你当各个子类中持有一些构造函数,他们之本体几乎完全一致。在超类中新盖一个构造函数,并于子类构造函数中调用其。
  4. 函数下转移(Push Down
    Method)。超类中的某部函数只及一些(而休全部)子类有关。将这个函数移到有关的那些子类去。
  5. 字段下转移(Push Down
    Field)。超类中之之一字段只受一些(而非全部)子类用到。将这字段移到要她的那些子类去。
  6. 提炼子类(Extract
    Subclass)。类中之一点特点只给一些(而无全部)实例用到。新建一个子类,将方面所说的那有些特色移到子类中。
  7. 提炼超类(Extract
    Superclass)。两单近乎闹一般特性。为当时半独八九不离十建立一个超类,将一律特性移至超类。
  8. 提炼接口(Extract
    Interface)。若干客户采用类似接口中之同一子集,或者个别个像样的接口有局部雷同。将一律之子集提炼到一个独接口中。
  9. 折叠继承体系(Collapse
    Hierarchy)。超类和子类之间无极其非常区别。将她合为一体。
  10. 培植模板函数(Form TemPlate
    Method)。你生出一些子类,其中相应的一些函数以同顺序执行类似之操作,但各个操作的细节上具有不同。将这些操作分别放上独立函数中,并保障其都发平等之签字,于是原函数为便更换得千篇一律了。然后用原来函数上换至超类。
  11. 以寄代继承(Replace Inheritance with
    Delegation)。某个子类只使用超类接口中之均等有,或是根本未需要继续而来的多少。在子类中初打一个字段用以保存超类;调整子类函数令它改变而委托超类;然后去丢两者之间的累关系。
  12. 因连续取代委托(Replace Delegation with
    Inheritance)。你在少数单类似里下委托关系,并时时为周接口编写许多顶简的嘱托函数。让委托类来就承受托类。

9、Substitute Algorithm
(替换算法)

十三、大型重构

  1. 梳理并讲继承体系(Tease Apart
    Inheritance)。某个继承体系以负责两码责任。建立两独持续体系,并由此信托关系被中一个可以调用另一个。
  2. 用过程化设计转化为目标设计(Convert Procedural Design to
    Objects)。你手上有局部习俗过程化风格的代码。将数据记录变成对象,将大块的所作所为分成小片,并将作为易入有关对象中。
  3. 用世界与发表/显示分离(Separate Domain from
    Presentation)。某些GUI类之中包含了世界逻辑。将世界逻辑分离出来,为她建立单独的领域接近。
  4. 提炼继承体系(Extract
    Hierarchy)。你产生某个号做了极多干活,其中一些干活是因大量谱表达式完成的。建立继续体系,以一个子类表示无异栽新鲜状况。

亚、在对象期间搬移特性

十四、经典语句

  1. Any fool can write code that a computer can understand. Good
    programmers write code that humans can understand.
    ——Martin
    Fowler

    其他一个傻子都能写有计算机可以清楚的代码。唯有写起人类容易理解的代码,才是美好的代码。
    ——Martin Fowler
  2. I’m not a great programmer; I’m just a good programmer with
    great habits.
    ——Kent Beck
    自己不是单光辉之程序员,我只是一个怀有一些好好习惯的好程序员。
    ——Kent Beck
  3. Computer Science is the discipline that believes all problems
    can be solved with one more layer of indirection.
    ——Dennis
    DeBruler

    计算机是是这么平等宗科学:它相信有题目还可以由此加一个间接层来化解。——Dennis
    DeBruler

10、Move Method
(搬移函数)

自身的体会:

  1. 读者最有必然的色阅,或者了解了有代码风格、设计模式、代码设计哲学等。
  2. 旋即是如出一辙论以java语言来讲重构的开,读者最好理解面向对象的基本知识,了解java、C++等面向对象的言语。
  3. 自莫是作java开发的,但是自己打听面向对象,了解C++,java。书中之一对答辩及点在其余计划语言达到啊时有发生酷死之帮忙,并且自己发现,在档次遭到自这即使当动用在有重构方法。书被那些过于结合面向对象的包、继承、多态等知之重构方法,可能就是光适用于面向对象的言语吧。
  4. **卿值得一诵读。反复看,反复读。 **

11、Move Field
(搬移字段)

自之胡说八道:

  1. 让你们发现了,其实自己吧是一个程序员,还是低档程序员。
  2. 当下按照书据说是java进阶必看,也是程序员必看之藏图书。设计语言本身也许发生分别,造成局部特点也会时有发生分别,但是一些思想要相通之。所有,非java、C++语言工作者,也必定要是读一下。
  3. 传说stack
    overflow.com上载之平等篇《哪一样本书最有影响力,是每个程序员都应读之?》。《重构》这仍开就行前十,貌似是第六称呼。

重构——改变既来代码的设计.jpg


ps:我的笔记只记录了理论部分,书上每种重构方法都配有实例代码来讲解,大家可以细细研究。

12、Extract Class
(提炼类)

13、Inline Class
(将看似内联化)

14、Hide Delegate
(隐藏委托关系)

15、Remove Middle Man
(移除中间人)

16、Introduce Foreign Method
(引入外加函数)

17、Introduce Local
Extension
(引入本地扩展)

老三、重新组织数据

18、Self Encapsulate Field
(自封装字段)

19、Replace Data Value with
Object
(以目标取代数据值)

20、Change Value to Reference
(将值对象改吧援对象)

21、Change Reference to
Value
(将引用对象改也价值对象)

22、Replace Array with Object
(以目标取代数组)

23、Duplicate Observed Data
(复制“被监视数据”)

24、Change Unidirectional
Association to Bidirectional
(将只有为关系改吗双向关联)

25、Change Bidirectional
Association to Unidirectional
(将双向关联改呢单为关系)

26、Replace Magic Number with
SymBolic Constant
(以字面常量取代魔法数)

27、Encapsulated Field
(封装字段)

28、Encapsulated Collection
(封装集合)

29、Replace Record with Data
Class
(以数据类取代记录)

30、Replace Type Code with
Class
(以类取代类型码)

31、Replace Type Code with
Subclass
(以子类取代类型码)

32、Replace Type Code with
State/Strategy
(以状态/策略取代类型码)

33、Replace Subclass with
Field
(以字段取代子类)

季、简化条件表达式

34、Decompose Conditional
(分解条件表达式)

35、Consolidate Conditional
Expression
(合并条件表达式)

36、Consolidate Duplicate
Conditional Fragments
(合并重复的标准有)

37、Remove Control Flag
(移除控制标记)

38、Replace Nested
Conditional with Guard Clauses
(以卫语句取代嵌套条件表达式)

39、Replace Conditional with
Polymorphism
(以多态取代条件表达式)

40、Introduce Null Object
(引入Null
对象)

41、Introduce Assertion
(引入断言)

五、简化函数调用

42、Rename Method
(函数改名)

43、Add Parameter
(添加参数)

44、Remove Parameter
(移除参数)

45、Separate Query form
Modifier
(将查询函数和修改函数分离)

46、Parameterize Method
(令函数携带参数)

47、Replace Parameter with
Explicit Methods
(以明确函数取代参数)

48、Preserve Whole Object
(保持对象完整)

49、Replace Parameter with
Methods
(以函数取代参数)

50、Introduce Parameter Object
(引入参数对象)

51、Remove Setting Method
(移除设置函数)

52、Hide Method
(隐藏函数)

53、Replace Constructor with
Factory Method
(以工厂函数取代构造函数)

54、Encapsulate Downcast
(封装向下转型)

55、Replace Error Code with
Exception
(以老取代错误码)

56、Replace Exception with
Test (以测试取代异常)

六、处理包括关系

57、Pull Up Field
(字段上转换)

58、Pull Up Method
(方法上换)

59、Pull Up Constructor Body
(构造函数本体上转移)

60、push down Method
(函数下转移)

61、push down field
(字段下移)

62、Extract Subclass
(提炼子类)

63、Extract Superclass
(提炼超类)

64、Extract Interface
(提炼接口)

65、Collapse Hierarch
(折叠继承体系)

66、Form Template Method
(塑造模板函数)

67、Replace Inheritance with
Delegation
(以寄托代表继承)

68、Replace Delegation with
Inheritance
(以持续取代委托)