《重构:改善既有代码的设计(第2版)》 ePUBw.COM 66个笔记
将第二阶段的代码提炼成独立的函数。
做法
每当看见一段代码在同时处理两件不同的事,我就想把它拆分成各自独立的模块,因为这样到了需要修改的时候,我就可以单独处理每个主题,而不必同时在脑子里考虑两个不同的主题。
6.11 拆分阶段(Split Phase
把所有计算派生数据的逻辑收拢到一处,这样始终可以在固定的地方找到和更新这些逻辑,避免到处重复。
6.10 函数组合成变换(Combine Functions into Transform)
如果发现一组函数形影不离地操作同一块数据(通常是将这块数据作为参数传递给函数),我就认为,是时候组建一个类了。
面向对象
6.9 函数组合成类(Combine Functions into Class)
Introduce Parameter Object
变量可以很好地解释一段程序在干什么
Rename Variable
如果想要搬移一处被广泛使用的数据,最好的办法往往是先以函数形式封装所有对该数据的访问。
Encapsulate Variable
一旦发现了更好的名字,就得尽快给函数改名。这样,下一次再看到这段代码时,我就不用再费力搞懂其中到底在干什么。
Change Function Declaration
反向重构:提炼变量
Inline Variable
“将新的名字暴露得更宽”的坏处则是需要额外的工作量。如果工作量很大,我会暂时搁下这个想法,稍后再用以查询取代临时变量
但如果这个变量名在更宽的上下文中也有意义,我就会考虑将其暴露出来,通常以函数的形式
如果这个名字只在当前的函数中有意义,那么提炼变量是个不错的选择
表达式有可能非常复杂而难以阅读。这种情况下,局部变量可以帮助我们将表达式分解为比较容易管理的形式。
动机
反向重构:内联变量
• 删除该函数的定义。
• 每次替换之后,执行测试
提炼变量
将这个函数的所有调用点都替换为函数本体。
• 找出这个函数的所有调用点。
如果该函数属于一个类,并且有子类继承了这个函数,那么就无法内联。
• 检查函数,确定它不具多态性。
做法
应该去掉这个函数,直接使用其中的代码
其内部代码和函数名称同样清晰易读
反向重构:提炼函数
Inline Function
至少将目标函数放在源函数的同级,这样我就能立即看出提炼的范围是否合理。
先提炼成嵌套函数,然后再将其移入新的上下文
如果真的有必要提炼一个函数并返回多个值,可以构造并返回一个记录对象—不过通常更好的办法还是回过头来重新处理局部变量,我常用的重构手法有以查询取代临时变量(178)和拆分变量(
让每个函数都只返回一个值
提炼代码段之外的代码也使用了这个变量。
糟糕
如果变量的初始化和使用离得有点儿远,可以用移动语句(223)把针对这个变量的操作放到一起。
可以将这个临时变量的声明移到被提炼代码段中,然后一起提炼出去
这个变量只在被提炼代码段中使用。
如果你发现源函数的参数被赋值,应该马上使用拆分变量(240)将其变成临时变量
复杂
如果被提炼代码段对局部变量赋值
简单
提炼代码段只是读取这些变量的值
• 查看其他代码是否有与被提炼的代码段相同或相似之处。如果有,考虑使用以函数调用取代内联代码(222)令其调用提炼出的新函数。
• 在源函数中,将被提炼代码段替换为对目标函数的调用。 • 测试。
• 所有变量都处理完之后,编译。
在提炼部分被赋值的局部变量太多,这时最好是先放弃提炼
• 仔细检查提炼出的代码,看看其中是否引用了作用域限于源函数、在提炼出的新函数中访问不到的变量。若是,以参数的形式将它们传递给新函数。
• 将待提炼的代码从源函数复制到新建的目标函数中。
• 创造一个新函数,根据这个函数的意图来对它命名
做法
你必须在命名上花心思
不用过早担心性能问题
我甚至经常会写一些只有1行代码的函数
一个函数一旦超过6行,就开始散发臭味
如果你需要花时间浏览一段代码才能弄清它到底在干什么,那么就应该将其提炼到一个函数中,并根据它所做的事为其命名
将意图与实现分开
反向重构:内联函数
◆ 第6章 第一组重构
Extract Function