重构手法-从新组织函数

 主要针对于Long Methods 算法

 主要重构手法:Extract Method 函数

  Tips: 若是在进行屡次提炼以后,意识到提炼所得的某些函数并无作任何实质事情,或若是须要回溯回复原先函数,就须要Inline Method(将一个函数调用动做替换为该函数本体)  测试

  Extract Method 最大的困难就是处理局部变量,而临时变量则是其中一个主要的困难源头。 spa

处理一个函数时,能够运用 Replace Temp with Query去掉全部可去掉的临时变量。若是不少地方使用了某个临时变量,先运用Split Temporary Variable将它变得比较容易替换 对象

若是临时变量实在太混乱,难以替换。这时候就须要使用Replace Method with Method Object  它能够分解哪怕最混乱的函数,代价则是引入一个新的类。 继承

若是在函数内给参数进行了赋值,那么得使用Remove Assignments to Parameters 递归

函数分解完毕后,若是发现算法能够改进从而使代码更清晰,则可使用Substitute Algorithm 引入更清晰的算法。 ip

1. Extract Method (提炼函数)

Summary: 

将一段代码放进一个独立函数中,并让函数名称解释该函数的用途 it

Motivation: 

  •  若是每一个函数的粒度都很小,那么函数被复用的机会就更大
  • 这会使高成函数读起来就像一系列注释
  • 若是函数都是细粒度,那么函数的复写也会更容易些

Mechanics: 

  • 建立一个新函数,根据这个函数的意图来对它命名(“作什么”而非“怎样作”)
  • 将提炼出的代码从原函数复制到新建的目标函数中
  • 仔细检查提炼出的代码,看看其中是否引用了“做用局限于原函数”的变量(包括局部变量和原函数参数)。
  • 检查是否有“仅用于被提炼代码段”的临时变量。若是有,在目标函数中将它们声明为临时变量。
  • 检查被提炼代码段,看看是否有任何局部变量的值被它改变。若是一个临时变量值被修改了,看看是否能够将被提炼代码段处理为一个查询,并将结果赋值给相关变量。若是很难这样作,或若是被修改的变量不止一个,你就不能仅仅将这段代码原封不动地提炼出来。你可能须要先使用Split Temporary Variable, 而后尝试提炼。也可使用Replace Temp with Query 将临时变量消灭掉。
  • 将被提炼代码段中须要读取的局部变量,当作参数传给目标函数。
  • 处理完全部局部变量后,进行编译。
  • 在原函数中,将被提炼代码段替换为对目标函数的调用。
  • 编译,测试。

2. Inline Method (内联函数)

Summary:

在函数调用点插入函数本体,而后移除该函数。 io

Motivation:

  • 函数内部代码和函数名称一样清晰易读,去掉非必要的间接性。
  • 有一群组织不甚合理的函数,能够将它们都内联到一个大型函数中,再从中提炼出组织合理的小型函数。实施Replace Method with Method Object以前先这么作,每每能够得到不错的效果。
  • 若是别人使用的太多间接层,使得系统中的全部函数都彷佛只是对另外一个函数的简单委托,形成繁琐的委托动做,这时可使用Inline Method。试着使用内联手法,找出有用的间接层,移除无用的间接层。

Mechanics:

  • 检查函数,肯定它不具多态性。(若是子类继承了这个函数,就不要将此函数内联,由于子类没法覆写一个根本不存在的函数。)
  • 找出这个函数的全部被调用点。
  • 将这个函数的全部被调用点都替换为函数本体
  • 编译,测试。
  • 删除该函数的定义。

Tips: 对于递归调用,多返回点,内联至另外一个对象中而该对象并没有提供访问函数等复杂状况,那么就不该该使用这个重构手法

3. Inline Temp(内联临时变量)

Summary:

将全部对该变量的引用动做,替换为对他赋值的那个表达式自身。

Motivation:

Inline Temp多半是做为Replace Temp with Query的一部分使用的,因此真正的动机出如今后者那儿。惟一单独使用Inline Temp的状况是:你发现某个临时变量被赋予某个函数调用的返回值。通常来讲,这样的临时变量不会有任何危害,能够放心地把它留在那儿。但若是这个临时变量妨碍了其余的重构手法,例如Extract Method,就应该将它内联化。

Mechanics:

  • 检查给临时变量赋值的语句,确保等号右边的表达式没有反作用。
  • 若是这个临时变量并未被声明为final,那就将它声明为final,而后编译。(这能够检查该临时变量是否真的只被赋值一次)
  • 找到该临时变量的全部引用点,将它们替换为“为临时变量赋值”的表达式。
  • 每次修改后,编译并测试。
  • 修改完全部引用点以后,删除该临时变量的声明和赋值语句。
  • 编译,测试。

4. Replace Temp with Query(以查询取代临时变量)

Summary:

将这个表达式提炼到一个独立的函数中。将这个临时变量的全部引用点替换为对新函数的调用。此后新函数就可被其余函数使用。

Motivation:

临时变量的问题在于:它们是暂时的,并且只能在所属函数内使用。因为临时变量只能在所属函数内可见,因此它们会驱使你写出更长的函数,由于只有这样你才能访问到须要的临时变量。若是把临时变量替换为一个查询,那么同一个类中的全部函数都将能够得到这份信息。这将带给你极大帮助,使你可以为这个类编写更清晰的代码。

Replace Temp with Query 每每是运用Extract Method以前必不可少的一个步骤。局部变量会使代码难以被提炼,因此应该尽量把它们替换为查询式。

这种重构手法较为简单的状况是:临时变量只被赋值一次,或者赋值给临时变量的表达式不受其余条件影响。其余状况比较棘手,但也有可能发生。可能须要先运用Split Temporary Variable 或Separate Query from Modifier 视状况变得简单一些,而后再替换临时变量。若是你想替换的临时变量是用来收集结果的(例如循环中的累加值),就须要将某些程序逻辑(如循环)复制到查询函数去。

Mechanics:

  • 找出只被赋值一次的临时变量。(若是某个临时变量被赋值超过一次,考虑使用 Split Temporary Variable)将它分割成多个变量
  • 将该临时变量声明为final(这可确保临时变量的确只被赋值一次)
  • 编译
  • 将“对该临时变量赋值”之语句的等号右侧部分提炼到一个独立函数中。(首先将函数声明为private。往后你可能会发现有更多类须要使用它,那时放松对它的保护也容易。其次,确保提炼出来的函数无任何反作用,也就是说该函数并不修改任何对象内容。若是它有反作用,就对它进行Separate Query from Modifier)
  • 编译,测试
  • 在该临时变量身上实施Inline Temp。
相关文章
相关标签/搜索