第一部分 修改机理 2
第1章 修改软件 2
1.1 修改软件的四个起因 2
1.1.1 添加特性和修正bug 2
1.1.2 改善设计 4
1.1.3 优化 4
1.1.4 综合起来 4
1.2 危险的修改 6
第2章 带着反馈工作 8
2.1 什么是单元测试 10
2.2 高层测试 12
2.3 测试覆盖 12
2.4 遗留代码修改算法 15
2.4.1 确定修改点 16
2.4.2 找出测试点 16
2.4.3 解依赖 16
2.4.4 编写测试 16
2.4.5 改动和重构 17
2.4.6 其他内容 17
第3章 感知和分离 18
3.1 伪装成合作者 19
3.1.1 伪对象 19
3.1.2 伪对象的两面性 22
3.1.3 伪对象手法的核心理念 23
3.1.4 仿对象 23
第4章 接缝模型 25
4.1 一大段文本 25
4.2 接缝 26
4.3 接缝类型 29
4.3.1 预处理期接缝 29
4.3.2 连接期接缝 32
4.3.3 对象接缝 35
第5章 工具 40
5.1 自动化重构工具 40
5.2 仿对象 42
5.3 单元测试用具 42
5.3.1 JUnit 43
5.3.2 CppUnitLite 44
5.3.3 NUnit 46
5.3.4 其他xUnit框架 46
5.4 一般测试用具 46
5.4.1 集成测试框架 47
5.4.2 Fitnesse 47
第二部分 修改代码的技术 50
第6章 时间紧迫,但必须修改 50
6.1 新生方法 52
6.2 新生类 54
6.3 外覆方法 58
6.4 外覆类 61
6.5 小结 66
第7章 漫长的修改 67
7.1 理解代码 67
7.2 时滞 67
7.3 解依赖 68
7.4 小结 73
第8章 添加特性 74
8.1 测试驱动开发 74
8.1.1 编写一个失败测试用例 75
8.1.2 让它通过编译 75
8.1.3 让测试通过 75
8.1.4 消除重复 76
8.1.5 编写一个失败测试用例 76
8.1.6 让它通过编译 76
8.1.7 让测试通过 77
8.1.8 消除重复代码 77
8.1.9 编写一个失败测试用例 77
8.1.10 让它通过编译 77
8.1.11 让测试通过 78
8.1.12 消除重复 79
8.2 差异式编程 80
8.3 小结 88
第9章 无法将类放入测试用具中 89
9.1 令人恼火的参数 89
9.2 隐藏依赖 95
9.3 构造块 98
9.4 恼人的全局依赖 100
9.5 可怕的包含依赖 107
9.6 “洋葱”参数 110
9.7 化名参数 112
第10章 无法在测试用具中运行方法 115
10.1 隐藏的方法 115
10.2 “有益的”语言特性 118
10.3 无法探知的副作用 121
第11章 修改时应当测试哪些方法 127
11.1 推测代码修改所产生的影响 127
11.2 前向推测 132
11.3 影响的传播 137
11.4 进行影响推测的工具 138
11.5 从影响分析当中学习 140
11.6 简化影响结构示意图 141
第12章 在同一地进行多处修改,是否应该将相关的所有类都解依赖 144
12.1 拦截点 145
12.1.1 简单的情形 145
12.1.2 高层拦截点 147
12.2 通过汇点来判断设计的好坏 150
12.3 汇点的陷阱 152
第13章 修改时应该怎样写测试 153
13.1 特征测试 153
13.2 刻画类 156
13.3 目标测试 157
13.4 编写特征测试的启发式方法 161
第14章 棘手的库依赖问题 162
第15章 到处都是API调用 164
第16章 对代码的理解不足 172
16.1 注记/草图 172
16.2 清单标注 173
16.2.1 职责分离 173
16.2.2 理解方法结构 174
16.2.3 方法提取 174
16.2.4 理解你的修改产生的影响 174
16.3 草稿式重构 174
16.4 删除不用的代码 175
第17章 应用毫无结构可言 176
17.1 讲述系统的故事 177
17.2 NakedCRC 180
17.3 反省你们的交流或讨论 182
第18章 测试代码碍手碍脚 184
18.1 类命名约定 184
18.2 测试代码放在哪儿 185
第19章 对非面向对象的项目,如何安全地对它进行修改 187
19.1 一个简单的案例 187
19.2 一个棘手的案例 188
19.3 添加新行为 191
19.4 利用面向对象的优势 193
19.5 一切都是面向对象 196
第20章 处理大类 199
20.1 职责识别 202
20.2 其他技术 213
20.3 继续前进 213
20.3.1 战略 213
20.3.2 战术 214
20.4 类提取之后 215
第21章 需要修改大量相同的代码 216
第22章 要修改一个巨型方法,却没法为它编写测试 232
22.1 巨型方法的种类 232
22.1.1 项目列表式方法 232
22.1.2 锯齿状方法 233
22.2 利用自动重构支持来对付巨型方法 236
22.3 手动重构的挑战 238
22.3.1 引入感知变量 239
22.3.2 只提取你所了解的 241
22.3.3 依赖收集 243
22.3.4 分解出方法对象 243
22.4 策略 244
22.4.1 主干提取 244
22.4.2 序列发现 244
22.4.3 优先提取到当前类中 245
22.4.4 小块提取 246
22.4.5 时刻准备重新提取 246
第23章 降低修改的风险 247
23.1 超感编辑 247
23.2 单一目标的编辑 248
23.3 签名保持 249
23.4 依靠编译器 251
第24章 当你感到绝望时 254
第三部分 解依赖技术 258
第25章 解依赖技术 258
25.1 参数适配 258
25.2 分解出方法对象 261
25.3 定义补全 266
25.4 封装全局引用 268
25.5 暴露静态方法 273
25.6 提取并重写调用 275
25.7 提取并重写工厂方法 276
25.8 提取并重写获取方法 278
25.9 实现提取 281
25.9.1 步骤 283
25.9.2 一个更复杂的例子 284
25.10 接口提取 285
25.11 引入实例委托 290
25.12 引入静态设置方法 292
25.13 连接替换 296
25.14 参数化构造函数 297
25.15 参数化方法 301
25.16 朴素化参数 302
25.17 特性提升 304
25.18 依赖下推 307
25.19 换函数为函数指针 310
25.20 以获取方法替换全局引用 313
25.21 子类化并重写方法 314
25.22 替换实例变量 317
25.23 模板重定义 320
25.24 文本重定义 323
附录 重构 325
术语表 329
索引 331