Extract Method 提炼函数
动机
Extract Method是我最常用的重构手法之一。当我看见一个过长的函数或者一段需要注释才能让人理解用途的代码,我就会将这段代码放进一个独立函数中。
有几个原因造成我喜欢简短而命名良好的函数。首先,如果每个函数的粒度都很小,那么函数被复用的机会就更大;其次,这会使高层函数读起來就像一系列注释:再次,如果函数都是细粒度,那么函数的覆写也会更容易些。
的确,如果你习惯看大型函数,恐怕需要一段时间才能适应这种新风格。而且只有当你能给小型函数很好地命名时,它们才能真正起作用,所以你需要在函数名称上下点功夫。人们有时会问我,一个函数多长才算合适?在我看来,长度不是问题,关键在于函数名称和函数本体之间的语义距离。如果提炼可以强化代码的清晰度,那就去做,就算函数名称比提炼出来的代码还长也无所谓。
做法
- 创造一个新函数,根据这个函数的意图来对它命名(以它“做什么”来命名,而不是以它“怎样做”命名)。
即使你想要提炼的代码非常简单,例如只是一条消息或一个函数调用,只要新函数的名称能够以更好方式昭示代码意图,你也应该提炼它。但如果你想不出一个更有意义的名称,就别动。
将提炼出的代码从源函数复制到新建的目标函数中。
仔细检査提炼出的代码,看看其中是否引用了“作用域限于源函数”的变量(包括局部变量和源函数参数)。
检査是否有“仅用于被提炼代码段”的临时变量。如果有,在目标函数中将它们声明为临时变量。
检查被提炼代码段,看看是否有任何局部变量的值被它改变。如果一个临时变量值被修改了,看看是否可以将被提炼代码段处理为一个査询,并将结果赋值给相关变量。如果很难这样做,或如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动地提炼出來。你可能需要先使用Spilt Temporary Variable,然后再尝试提炼。也可以使用Replace Temp with Query将临时变量消灭掉。
将被提炼代码段中需要读取的局部变最,当作参数传给目标函数。
处理完所有局部变量之后,进行编译。
在源函数中,将被提炼代码段替换为对目标函数的调用。
如果你将任何临时变量移到目标函数中,请检查它们原本的声明式是否在被提炼代码段的外围。如果是,现在你可以删除这些声明式了。
- 编译,测试。