第6章 第一组重构
提炼函数
- 何时应该把代码放进独立的函数,一个合理的观点是“将意图与实现分开”。
- 当变量按值传递给提炼部分又在提炼部分被赋值,就必须多加小心。如果只有一个这样的变量,我会尝试将提炼出的新函数变成一个查询(query),用其返回值给该变量赋值。
- 但有时在提炼部分被赋值的局部变量太多,这时最好是先放弃提炼,考虑其他重构手法,拆分变量或者以查询取代临时变量。
内联函数
- 略
提炼变量
- 表达式有可能非常复杂而难以阅读,这种情况下,局部变量可以帮助我们将表达式分解为比较容易管理的形式。
- 注意声明为不可修改的变量。
内联变量
- 略
改变函数声明
- 略
封装变量
- 如果想要搬移一份广泛使用的数据,最好的办法往往是以函数形式封装所有对该数据的访问。
- 在类的内部,是否应该通过访问函数来使用字段?这种做法也被称为“自封装”。作者认为自封装有点过度了,如果一个类大到需要将字段自封装起来,那么首先应该考虑把这个类拆小。
- 封装数据重要,但是不可变数据更重要。
- 封装数据还有一个细节,使用Get访问器确保了不修改数据的引用,但是不能控制对数据内容的修改。这时有两种办法:
- 对于列表数据,在取值函数中返回数据的一份副本。
- 另一种做法是阻止对数据的修改,通过封装记录,来实现这一效果。
变量改名
- 略
引入参数对象
- 函数输入参数里,如果有经常结伴同行的数据项,就应该提取成一个数据结构(类)。这里要注意最好做成值类型。后续可以将相关的操作,都放在这个数据结构(类)里。C#中struct也可以封装自己的方法。
函数组成类
- 将函数组合成类,可以让函数与其处理的数据在空间上有更紧密的联系。如果只是将相同或逻辑的函数提取到一起,读者不一定想到来这里找它。
函数组合成变换
- 程序中常常需要根据一个数据计算出各种派生信息。对应这种办法的方法是,采用数据变换函数,这种函数接收源数据作为输入,计算出所有的派生数据。
- 如果输出还包含元数据,使用深复制将源数据复制出来。
- 注意一个问题:通过变换获得的函数其实是源数据的数据记录。如果某个地方修改了源数据的值,就会导致数据不一致。当会有这种情况出现时,建议采用函数组成类的重构手法。
拆分阶段
- 将大段行为分成顺序执行的两个阶段。中间使用要给中转数据结构。