重构手法-重新组织函数

 主要针对于Long Methods

 主要重构手法:Extract Method

  Tips: 如果在进行多次提炼之后,意识到提炼所得的某些函数并没有做任何实质事情,或如果需要回溯回复原先函数,就需要Inline Method(将一个函数调用动作替换为该函数本体) 

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

处理一个函数时,可以运用 Replace Temp with Query去掉所有可去掉的临时变量。如果很多地方使用了某个临时变量,先运用Split Temporary Variable将它变得比较容易替换

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

如果在函数内给参数进行了赋值,那么得使用Remove Assignments to Parameters

函数分解完毕后,如果发现算法可以改进从而使代码更清晰,则可以使用Substitute Algorithm 引入更清晰的算法。

1. Extract Method (提炼函数)

Summary: 

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

Motivation: 
  •  如果每个函数的粒度都很小,那么函数被复用的机会就更大
  • 这会使高成函数读起来就像一系列注释
  • 如果函数都是细粒度,那么函数的复写也会更容易些
Mechanics: 
  • 创建一个新函数,根据这个函数的意图来对它命名(“做什么”而非“怎样做”)
  • 将提炼出的代码从原函数复制到新建的目标函数中
  • 仔细检查提炼出的代码,看看其中是否引用了“作用局限于原函数”的变量(包括局部变量和原函数参数)。
  • 检查是否有“仅用于被提炼代码段”的临时变量。如果有,在目标函数中将它们声明为临时变量。
  • 检查被提炼代码段,看看是否有任何局部变量的值被它改变。如果一个临时变量值被修改了,看看是否可以将被提炼代码段处理为一个查询,并将结果赋值给相关变量。如果很难这样做,或如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动地提炼出来。你可能需要先使用Split Temporary Variable, 然后尝试提炼。也可以使用Replace Temp with Query 将临时变量消灭掉。
  • 将被提炼代码段中需要读取的局部变量,当做参数传给目标函数。
  • 处理完所有局部变量后,进行编译。
  • 在原函数中,将被提炼代码段替换为对目标函数的调用。
  • 编译,测试。

2. Inline Method (内联函数)

Summary:

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

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。

转载于:https://my.oschina.net/u/134516/blog/122817

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值