定义
重构是在不改变软件可观察行为的前提下改善其内部结构。
任何不会被修改的变量都可以当成参数传入新的函数,会被修改的变量要格外小心。
如果只有一个变量会被修改,可以把它当做返回值。
尽量去除临时变量,因为临时变量会被当成参数传来传去,容易跟丢它们。
第三章-代码坏味道
- 重复代码
- 同一个类的两个函数含有相同的表达式
- 两个互为兄弟的子类内含相同表达式
- 2个毫不相关的类出现重复代码
- 过长函数
- 每当感觉需要以注释来说明点说明的时候,我们就需要把说明的东西写进一个独立函数中,并以用途命名,不是用实现手法命名。
- 有注释的地方就该提炼代码到独立函数中,哪怕只有一行代码。
- 条件表达式和循环也可以提炼。可以将循环和其内部代码提炼到独立函数中。
- 过大的类,可以将彼此相关的成员变量放到一起,提炼到新的子类。
- 过长参数列,尽量将参数放到一个对象中
- 少用switch,可以考虑使用多态来替代它
- 没用的类可以删掉,不然你所创建的每个类都得有人去理解它,维护它,这都是有成本的。对于几乎没用的类,可以用内部类对付。
- 如果一个类的某个实例变量仅为某种特定情况而设置的,这样的代码会让人难以理解,因为在变量未被设置值的时候还需要猜测它的用途,这时候应该把这些变量,和跟这个变量相关的方法抽取到新的类里。
- 如果两个函数做同一件事,确有不同的函数命名,应该根据用途,将函数重新命名,并且移入相关的类中,直到两者表达的含义正确。
- 过多的注释,当你感觉需要些注释时,尝试先重构,试着让所有注释都变得多余。注释可以写为什么要做某某事。
第六章-组织函数
提炼函数
定义:将代码放进一个独立函数中,并用函数名称解释该函数的用途。
当看到一个过长的函数或者需要一段注释才能理解的代码时,就可以考虑提炼函数。
函数简短的好处:
- 函数的粒度越小,越容易被复用,复写也会更容易。
- 高层函数读起来就像读一系列注释。
关键:
- 函数命名一定要正确,如果提炼可以强化代码的清晰度就可以做。
- 函数命名要以他做什么来命名,而不是它怎么做,如果你想不出有意义的命名就别动。
- 无局部变量则直接提炼函数即可
- 如果有局部变量,但是新函数只是读取它,并不修改它,那就当做参数传给目标函数。
- 如果对局部变量发生赋值操作,如果变量只是在被提炼代码中使用,可以将变量在被提炼代码中声明。否则就让目标函数返回该变量改变后的值。
- 如果被提炼的函数需要返回多个值,那就挑选另外的函数进行提炼,保证返回值只有一个
内联函数
定义: 一个函数的本体与名称同样清楚易懂。在函数调用点插入函数本体,然后移除该函数。
关键:
- 当函数的内部代码和函数名称同样清晰易读,可以考虑去掉这个函数。
内联临时变量
定义:如果你有一个临时变量,只被一个简单表达式赋值1次,而它妨碍了其他重构手法,那就将所有对该变量的引用动作,替换为对它复制的那个表达式本身。
以查询取代临时变量
定义:你的程序以一个临时变量保存某一表达式的运算结果,那就将这个表达式提炼到一个独立函数中,将这个临时变量的所有引用点替换为对新函数的调用。此后,新函数就可被其他函数使用。
引入解释性变量
你有一个复杂的表达式,将该复杂表达式(或其中一部分)的结果放进一个临时变量,并用此变量名称来解释表达式用途。
分解临时变量
你的程序有某个临时变量被复制超过1次,但是它既不是循环变量,也不是用于收集计算结果,那么针对每次赋值,应该创建一个独立,对应的临时变量。
如果临时变量只是用于保存一段冗长代码的运算结果,以便后续使用,那么这种变量应该只被赋值1次,如果被赋值超过多次,说明这个变量承担了一个以上的责任,会令代码阅读者糊涂,每个变量应该只承担一个责任。
移除对参数的赋值
代码对一个参数进行赋值,那就用一个临时变量取代该参数的位置。
以函数对象取代函数
替换算法
第九章 简化条件表达式
总结
- 分解条件表达式,将复杂的的条件提炼出新的函数。
- 将可以合并的条件表达式进行合并。
- 合并重复的条件片段,抽离出变化和不变的内容。
- 使用break和return,卫语句,提前返回函数。
- 使用多态替代switch表达式。
分解条件表达式
合并条件表达式
合并重复的条件片段
移除控制标记
使用卫语句,取代嵌套条件表达式
用多态取代条件表达式
引入NULL对象
引入断言
第十章 简化函数调用
总结
- 给函数取一个好名字,想办法将注释变成函数名称
- 函数入参尽量使用对象,保证入参的简短。
- 将查询函数和修改函数分开,一个负责查询,一个负责修改
- 用异常取代错误码,可以预先检查的条件,可以在调用函数之前先做检查,即提前返回函数。
- 如果函数做了类似的工作,那就建立单一的函数,通过参数表达不同的值
- 如果参数可以通过函数获取,则去掉该参数,改为通过函数获取。
- 如果函数没有被其他类使用,则设置为private
函数改名
添加参数
移除参数
和添加参数同理
将查询函数和修改函数分离
注意并发问题
令函数携带参数
以明确函数取代参数
尤其是switch或者if分支的用途