重构-改善既有代码的设计

重构是在不改变软件可观察行为的前提下改善其内部结构。

有一句古老的工程谚语:如果它还可以运行,就不要动它。对吗?

第一章 重构第一个案例

  • 如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构那个程序,使特性的添加比较容易进行,然后再添加特性。
  • 重构第一步:为即将修改的代码建立一组可靠的测试环境,有自我校验的能力,提高重构速度。用现有的程序跑出测试用例,测试用例尽可能全。输入跟输出,然后留存方便重构后的代码进行校验。
  • 重构步骤的本质,由于每次修改的幅度都很小,所以任何错误都很容易发现。你不必耗费大把时间调试。
  • 任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员。
  • 重构的节奏:测试,小修改,测试,小修改,测试,小修改。。。。。。正是这种节奏让重构得以快速而安全的前进。

第二章 重构原则

  • 重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
  • 重构(动词):使用一系列重构手段,在不改变软件可观察行为的前提下,调整其结构。
  • 重构的目的:1. 改进软件设计。 2. 使软件更易于理解。3.重构帮助找到bug 4. 重构提高编程速度
  • 事不过三,三则重构。1. 添加新功能时重构 2. 修补错误时重构 3. 复审代码时重构
    1. 难以阅读的程序,难以修改。2.逻辑重复的程序,难以修改。 3. 添加新行为时需要修改已有代码的程序,难以修改。 4. 带复杂条件逻辑的程序,难以修改。
  • 希望 1. 容易阅读 2 所有逻辑都只在唯一地点指定 3. 新的改动不会危及现有行为 4. 尽可能简单表达条件逻辑
  • 计算机科学时这样一门科学:它相信所有问题都可以通过增加一个间接层来解决。
  • 间接层和重构。简介层的价值:1 允许逻辑共享 2. 分开解释意图和实现 3.隔离变化 4. 封装条件逻辑
  • 不要过早发布接口,请修改你的代码所有权政策,使重构更顺畅。

第三章 代码的坏味道

  • Duplicated Code
  • Long Method
  • Large Class
  • Long Parameter List
  • Divergent Change 发散式变化
  • Shotgun Surgery 散弹式修改
  • Feature Envy 依恋情结
  • Data Clumps 数据泥团
  • Primitive Obsession 基本类型偏执
  • Switch Statements switch 惊悚现身
  • Parallel InheritanceHierarchies 平行继承体系
  • Lazy Class 冗赘类
  • Speculative Generality 夸夸其谈未来性
  • Temporary Field 令人迷惑的暂时字段
  • Message Chains 过度耦合的消息链
  • Middle Man 中间人
  • Inappropriate Intimacy
  • Alternative Class with Different Interfaces 异曲同工的类
  • Incomplete Library Class 不完美的库类
  • Data Class
  • Refused Bequest 被拒绝的遗赠
  • Comments 过多的注释,当你感觉需要写注释时,请先尝试重试,试着让所有注释都变得多余。当你不知道该做什么才是注释良好运用时机。

第四章 构筑测试体系

  • 确保所有测试都完全自动化,让他们检查自己的测试结果
  • 一套测试就是一个强大的bug侦测器,能够大大缩减查找bug所需要的时间
  • 频繁地运行测试,每次编译请把测试也考虑进去,每天至少执行每个测试一次。
  • 每当你收到bug报告,请先写一个单元测试来暴漏bug。
  • 测试用例主要是测试你最担心出错的部分。
  • 考虑可能出错的边界条件,把测试火力集中在那儿。
  • 当事情被认为应该会出错时,别忘了检查是否抛出了预期的异常。
  • 不要因为测试无法捕捉所有bug就不写测试,因为测试的确可以捕捉到大多数bug。
  • 花合理时间抓住大多数bug,好过,穷尽一生抓尽所有bug。

第五章 重构列表

  • 重构手法,名称,简单概要,动机,做法,范例
  • 寻找引用点。
  • 这些重构手法有多成熟?

第六章 重新组织函数

  • Extract Method 提炼函数
  • Inline Method 内联函数
  • Inline Temp 内联临时变量
  • Relace Temp with Query 以查询取代临时变量
  • Introduce Explaining Variable 引入解释性变量
  • Split Temporary Variable 分解临时变量
  • Remove Assignments to Parameters 移除对参数的赋值
  • Relace Method with Method Object 以函数对象取代函数
  • Substitue Algorithm 替换算法

第七章 在对象之间搬移特性

  • Move Method 搬移函数
  • Move Field 搬移字段
  • Extract Class 提炼类
  • Inline Class 将类内联化
  • Hide Delegate 隐藏 “委托关系”
  • Remove Middle Man 移除中间人
  • Introduce Foreign Method 引入外加函数
  • Introduce Local Extension 引入本地扩展

第八章 重新组织数据

  • Self Encapsulate Fiedl 自封装字段
  • Replace Data Value with Object 以对象取代数据值
  • Change Value to Reference 将值对象改为引用对象
  • Change Reference to Value 将引用对象改为值对象
  • Replace Array with Object 以对象取代数组
  • Duplicate Observed Data 复制”被监视数据“
  • Change Unidirectional Association to Bidiredctional 将单向关联改为双向关联
  • Change Bidiredctional Association to Unidirectional 将双向关联改为单向关联
  • Replace Magic Number with Symbolic Constant 以字面常量取代魔法数
  • Encapusulate Field 封装字段
  • Encapsulate Collection 封装集合
  • Relace Record with Data Class 以数据类取代记录
  • Replace Type Code with Class 以类取代类型码
  • Replace Type Code with Subclasses 以子类取代类型码
  • Replace Type Code with State/Strategy 以State/Strategy取代类型码
  • Replace Subclass with Fields 以字段取代子类

第九章 简化条件表达式

  • Decompose Conditional 分解条件表达式
  • Consolidate Conditional Expression 合并条件表达式
  • Consolidate Duplicate Conditional Fragments 合并重复的条件片段
  • Remove Control Flag 移除控制标记
  • Replace Nested Conditional with Guard Clauses 以卫语句取代嵌套条件表达式
  • Replace Conditional with Polymorphism 以多态取代条件表达式
  • Introduce Null Object 引入Null对象
  • Introduce Assertion 引入断言

第十章 简化函数调用

  • Rename Method 函数改名
  • Add Parameter 添加参数
  • Remove Parameter 移除参数
  • Separate Query from Modifier 将查询函数和修改函数分离
  • Parameterize Method 令函数携带参数
  • Replace Parameter with Explicit Methods 以明确函数取代参数
  • Preserve Whole Object 保持对象完整
  • Replace Parameter with Methods 以函数取代参数
  • Introduce Parameter Object 引入参数对象
  • Remove Setting Method 移除设值函数
  • Hide Method 隐藏函数
  • Replace Constructor with Factory Method 以工厂函数取代构造函数
  • Encapsulate Downcast 封装向下转型
  • Replace Error Code with Exception 以异常取代错误码
  • Replace Exception with Test 以测试取代异常

第十一章 处理概括关系

  • Pull Up Field 字段上移
  • Pull Up Method 函数上移
  • Pull Up Constructor Body 构造函数本体上移
  • Push Down Method 函数下移
  • Push Down Field 字段下移
  • Extract Subclass 提炼子类
  • Extract Superclass 提炼超类
  • Extract Interface 提炼接口
  • Collapse Hierarchy 折叠继承体系
  • Form TemPlate Method 塑造模版函数
  • Replace Inheritance with Delegation 以委托取代继承
  • Replace Delegation with Inheritance 以继承取代委托

第十二章 大型重构

  • 小小的信仰:每天都使自己的程序世界更安全
  • Tease Apart Inheritance 梳理并分解继承体系
  • Convert Procedural Design to Objects 将过程化设计转化为对象设计
  • Separate Domain from Presentation 将领域和表述/显示分离
  • Extract Hierarchy 提炼继承体系

第十三章 重构,复用与实现

第十四章 重构工具

  • 重构与新功能需要同时进行
  • Refactoring Browser

第十五章 总结

  • 随时挑一个目标
  • 没把我就停下来
  • 学习原路返回
  • 二重奏

要点列表

  • 如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构那个程序,使特性的添加比较容易进行,然后再添加特性。
  • 重构前先检查自己是否有一套可靠的测试机制,这些测试机制必须有一套自我检验能力
  • 重构技术就是以微小的步伐修改程序。如果你犯下错误,很容易便可发现它。
  • 任何傻瓜都能写出计算机可以理解的代码,唯有写出人类容易理解的代码才是优秀的程序员
  • 重构,对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
  • 重构:使用一系列重构手法,在不改变软件可观察行为的前提下,调整其机构。
  • 事不过三,三则重构
  • 不要过早发布接口,请修改你的大米所有权策略,使重构更顺畅。
  • 当感觉需要写注释时,请尝试重构,让所有注释都变得多余
  • 确保所有测试都完全自动化,让它们检查自己的测试结果
  • 一套测试就是一个强大的bug侦测器,能够大大缩减查找bug所需要的时间。
  • 频繁地运行测试,每次编译请把测试也考虑进去,每天至少执行每个测试一次。!!!!!
  • 每当你收到bug报告,请先写一个测试用例来暴漏这个bug
  • 考虑可能出错的边界条件,把测试火力集中在那儿。
  • 当事情被大家认为应该会出错时,别忘了检查是否抛出了预期的异常
  • 不要应为测试无法捕捉到所有bug就不写测试,因为测试的确可以捕捉到大多数bug

END