重构-改善既有代码的设计
2017-07-26重构是在不改变软件可观察行为的前提下改善其内部结构。
有一句古老的工程谚语:如果它还可以运行,就不要动它。对吗?
第一章 重构第一个案例
- 如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构那个程序,使特性的添加比较容易进行,然后再添加特性。
- 重构第一步:为即将修改的代码建立一组可靠的测试环境,有自我校验的能力,提高重构速度。用现有的程序跑出测试用例,测试用例尽可能全。输入跟输出,然后留存方便重构后的代码进行校验。
- 重构步骤的本质,由于每次修改的幅度都很小,所以任何错误都很容易发现。你不必耗费大把时间调试。
- 任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员。
- 重构的节奏:测试,小修改,测试,小修改,测试,小修改。。。。。。正是这种节奏让重构得以快速而安全的前进。
第二章 重构原则
- 重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
- 重构(动词):使用一系列重构手段,在不改变软件可观察行为的前提下,调整其结构。
- 重构的目的:1. 改进软件设计。 2. 使软件更易于理解。3.重构帮助找到bug 4. 重构提高编程速度
- 事不过三,三则重构。1. 添加新功能时重构 2. 修补错误时重构 3. 复审代码时重构
-
- 难以阅读的程序,难以修改。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