第五章 重构列表
重构的记录格式
- 建造一个重构词汇表
- 一个简短概要,解决的问题,应该做的事,展示重构前后示例
- 动机,为什么要重构
- 做法,介绍如何进行此一重构
- 范例,说明重构手法如何运作
寻找引用点
- 利用文本查找工具,检查是否有其他类声明了正在处理的那个函数
重构手法的成熟度
- 重构的基本技巧——小步前进、频繁测试
第六章 重新组织函数
Extract Method(提炼函数)
- 动机:看见一个过长的函数或者一段需要注释才能让人理解用途的代码
- 做法:
- 创造一个新函数,并根据这个函数的意图来对它明明
- 将提炼出的代码从源函数复制到新建的目标函数中
- 仔细检查提炼出的代码,看看其中是否引用了"作用于限于源函数"的变量
- 检查被提炼代码段,看看是否有任何局部变量的值被它改变
- 将被提炼代码段中需要读取的局部变量,当作仓鼠传给目标函数
- 处理完所有局部变量之后,进行编译
- 在源函数中,将被提炼代码替换为对目标函数的调用
- 编译测试
Inline Method(内联函数)
- 动机:手上有一群组织不合理的函数,可以将它们内联到一个大型函数中,再从中提炼出组织合理的小型函数
- 做法
- 检查函数,确定它不具多态性
- 找出这个函数的所有被调用点
- 将这个函数的所有被调用点都替换为函数本体
- 编译测试
- 删除该函数定义
Inline Temp(内联临时变量)
- 动机:发现某个临时变量被赋予某个函数调用的返回值。一般来说,这种临时变量不会有任何危害,但该临时变量妨碍了其他的重构手法,就应该将它内联化
- 做法:
- 检查给临时变量赋值的语句,确保等号右边的表达式没有副作用
- 如果临时变量并未被声明为final,那就将它声明为final,然后编译
- 找到该临时变量的所有引用点,将它们替换为"临时变量复制"的表达式
- 每次修改后,编译并测试
- 修改完所有引用点之后,删除该临时变量的声明和赋值局域
- 编译测试
Replace Temp with Query(以查询取代临时变量)
- 动机:临时变量的问题在于它使暂时的,且只能在所属函数内使用。由于临时变量只在所属函数内可见,所以它们会驱使你写出更长的函数
- 做法:
- 找出只被赋值一次的临时变量
- 将该临时变量声明为final
- 编译
- 将"对该临时变量赋值"
- 编译测试
- 在该临时变量身上实施Inline Temp
Introduce Explaining Variable(引入解释性变量)
- 动机:表达式有可能非常复杂而难以阅读
- 做法:
- 声明一个final临时变量,将待分解之复杂表达式中的一部分动作的运算结果赋值给它
- 将表达式中的"运算结果"这一部分,替换为上述临时变量
- 编译测试
- 重复上述过程,处理表达式的其他部分
Split Temporary Variable(分解临时变量)
- 动机:临时变量有各种不同用途,部分变量会很自然地导致临时变量被多次赋值
- 做法:
- 在待分解临时变量的声明及其第一次被赋值处,修改其名称
- 将新的临时变量声明为final
- 以该临时变量的第二次赋值动作为界,修改此前对该临时变量的所有引用点,让它们引用新的临时变量
- 在第二次赋值处,重新声明原先那个临时变量
- 编译测试
- 逐次重复上述过程,每次都在声明处对临时变量改名,并修改下次赋值之前的引用点
Remove Assignments to Parameters(移除对参数的赋值)
- 动机:混用了按值传递和按引用传递这两种参数传递方式
- 做法:
- 建立一个临时变量,把待处理的参数值赋予它
- 以"对参数的赋值"为界,将其后所有对此参数的引用点,全部替换为"对此临时变量的引用"
- 修改赋值语句,使其改为对新建的临时变量赋值
- 编译测试
Replace Method with Method Object(以函数对象取代函数)
- 动机:发现根本无法拆解一个需要拆解的函数,可以将所有局部变量都变成函数对象的字段,将原本的大型函数拆解变短
- 做法:
- 建立一个新类,根据待处理函数用途进行命名
- 在新类中建立一个final字段,用以保存原先大型函数所在的对象
- 在新类中建议一个构造函数,接受源对象及原函数的所有参数作为参数
- 在新类中建立一个compute()函数
- 将原函数的代码复制到compute()函数中
- 编译
- 将旧函数的函数本体替换掉
Substitute Algorithm(替换算法)
- 动机:如果发现做一件事可以有更清晰的方式,就应该以较清晰的方式取代复杂的方式
- 做法:
- 准备好另一个(替换用)算法,让它通过编译
- 针对现有测试,执行上述的新算法。如果结果与原本结果相同,重构结束
- 如果测试结果不同于原先,在测试和调试过程中,以旧算法为比较参照标准