《测试驱动开发―31重构》

调和差异(Reconcile Difference)

怎样统一两段开起来相似的代码呢?一点一点地减少它们之间的差异,只有当它们完全一致的时候才去统一他们。

      重构是非常伤脑筋的工作。简单的东西一目了然。如果我们提取一种方法能够机械且正确地完成的话,那么改变系统行为的几率是非常小的。但是有一些重构要求你要仔细检查控制流程和数据值。一长串的推理将使你相信你将做的改变不会使任何现有答案发生改变。这些就是那种能够提高你处理问题能力的重构。

      这种超出可信度的重构恰恰是我们力图通过小步骤和具体反馈的策略所要避免的。尽管我们不能避免所有这种重构,但却可以减轻其带来的影响。

这种重构可以在各种规模层次上进行。

  • 如果两个循环结构类似,那么通过使其完全一致,我们可以将二者合并。
  • 如果一个判定语句的两个分支类似,我们通过使其完全一致,我们可以去掉这个条件判断。
  • 如果两个方法类似,那么通过使其完全一致,我们可以去掉其中一个方法。
  • 如果两个类类似,我们通过使其完全一致,我们可以去掉其中一个。  

隔离变化(Isolate Change)

怎样改变具有多个部分的方法或对象的某一部分?首先,对要修改的部分进行隔离。

一旦隔离了变化部分并进行了修改,你会发现其对结果的影响是如此直销以至于我们可以取消隔离。如果发现我们需要做的只是findRate()函数中返回一个实例变量,那么我们可以考虑在用到这个方法的地方一内联的方式插入findRate()的代码并删除这一方法。但是,不要不假思索地做这些改动,要权衡一下添加一种方法在代码中显示地增加某一概念的价值。

一些可能的隔离变化的方法有提取方法(Extract Method)(最常用的)、提取对象(Extract Object)和方法对象(Method Object)。


数据迁移(Migrate data)

怎样从一种数据表示形式迁移至另外一种形式呢?临时制作冗余数据。

怎样实现?

这是一种由内而为的迁移方式,即改变内部的表示形式,然后改变外部的可见接口。

  • 增加以新的数据格式表示的实例变量。
  • 在所有设置旧格式变量(format variable)的地方设置新的格式变量。
  • 在任何使用旧格式的地方使用新的格式变量。
  • 删除原先的格式。
  • 改变外部接口以反映这种新的格式。
然而有时候你想要先改变API,那么就应该这样做:
  • 增加一个以新数据格式表示的参数。
  • 降新数据格式的参数转换成内部原先的数据格式表示。
  • 删除旧格式的参数。
  • 将使用旧格式的地方转成使用新格式。
  • 删除旧格式。

提取方法(Extract Method)

怎样使一个既长又复杂的方法比较容易读懂呢?将其中一小部分转变成一个单独的方法并调用这个新的方法。
怎样实现?
提取方法实际上是一种比较复杂的原子级(atomic)重构,它是以自动化方式完成的重构,因此不比手工实现。
  • 在方法中寻找一块可以单独独立出来形成方法的区域。循环体、整个循环以及条件语句的分支都是常见的可供提取的部分。
  • 保证在要提取的区域内不存在向在本区域外声明的临时变量赋值的语句。
  • 将这部分代码从原来的方法中复制到新方法中,然后编译。
  • 对于将在新方法中用到的原方法中的每个临时变量或参数,都为新方法增加一个参数。
  • 在原来的方法中调用新方法。

内联方法(Inline Method)

如何简化变得过于繁琐或分散的控制流程呢?在调用方法的地方讲方法本身内联起来。

怎样实现呢?

  • 复制方法。
  • 在调用语句处黏贴该方法。
  • 将所有形参(formal parameter)替换成实参(actual parameter)。

提取接口(Extract Interface)

在Java中,怎样引进操作的另一种实现呢?创建一个包含该共享操作的接口。

怎样实现呢?

  • 声明一个接口。有时一个现有类的名字就应当是这个接口的名字,在这种情况下,你首先要重命名这个类。
  • 让现有的累实现这个接口。
  • 向接口中添加必要的方法,必要的话,在类中扩展方法的可见性。
  • 在可能的地方讲类型声明从类改为接口。

转移方法(Move Method)

怎样把一个方法转移到它所归属的地方?把它添加到所归属的那个累中,然后调用它。

怎样实现?

  • 复制方法。
  • 在目标类中黏贴方法,并适当命名,然后编译。
  • 如果方法引用了原来的对象,那么就加一个参数来传递原来的对象。如果方法引用了员对象中的变量,那么就把这些变量作为参数传递进来。如果原对象中的变量是设置好的,那么你就应该放弃这么做了。
  • 将原方法替换成新方法的调用。

方法对象(Method Object)

怎样表示一个复杂的需要若干参数和局部变量的方法?为该方法创建一个对象。

怎样实现?

  • 使用与方法一样的参数来创建一个对象。
  • 把局部变量变成对象的实例变量。
  • 创建一个run()的方法,使其内容与原来内容相同。
  • 在原方法中,创建一个新的对象,然后调用run()。

添加参数(Add Parameter)

怎样把参数添加到方法中?

怎样实现?

  • 如果方法在一个接口中,那么先在该接口中添加参数。
  • 添加参数
  • 使用编译时出错信息来指导你需要修改哪些调用代码。
把方法中的参数转变为构造函数中的参数
怎样把一个参数从一个或多个方法中转移到构造函数中呢?
怎样实现?
  • 在构造函数中添加一个参数。
  • 添加一个名称与该参数名相同的实例变量。
  • 在构造函数中设置变量。
  • 一个接一个地把“parameter”的引用改为对“this.parameter”的引用。
  • 当不存在对参数的引用时,从方法和所用的调用者中删除这个参数。
  • 从引用中删除现在多余的"this"。
  • 正常地重命名变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流媒体程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值