《重构改善既有代码的设计》之重构列表--简化函数调用(一)

一、Rename Method(函数改名)

函数的名称未能揭示函数的用途

修改函数名称

动机

函数的名称应该准确表达它的用途。给函数命名有一个好的方法:首先考虑应该给这个函数写上一句怎样的注释,然后想办法将注释变成函数名称。

做法

1、检查函数签名是否被超类或子类实现过。如果是,则需要针对每份实现分别进行下列步骤。

2、声明一个新函数,将它命名为你想要的名称。将旧函数代码复制到新函数中,并进行适当的调整。

3、编译。

4、修改旧函数,令它将调用转发给新函数。

5、编译,测试

6、找出旧函数的所有被引用点,修改它们,令它们改而引用新函数。每次修改后,编译并测试。

7、删除旧函数。

如果旧函数是该类的public接口的一部分,你可能无法安全的删除它。这种情况下,将它保留在原处,并将它标记为deprecated(建议不使用)

8、编译测试。

二、Add Parameters(添加参数)

某个函数需要从调用端得到更多信息。

为此函数添加一个对象参数,让该对象带进函数所需信息。

动机

Add Parameters是一个很常见的重构手法,我几乎可以肯定你已经用过它了。使用这项重构的动机很简单:你必须修改一个函数,而修改后的函数需要一些过去没有的信息,因此你需要给该函数添加一个参数。

实际上我要说明的是:不使用本项重构的时机。除了添加参数外,你常常还有其他选择。只要可能,其他选择都比添加参数要好,因为它们不会增加参数列的长度。

做法

1、检查函数签名是否被超类或子类实现过。如果是,则需要针对每份实现分别进行一下步骤。

2、声明一个新函数,名称与原函数相同,只是加上新添参数。将旧函数的代码复制到新函数中。

3、编译

4、修改旧函数,令它调用新函数。

5、编译,测试

6、找出旧函数的所有被引用点,将它们全部修改为新函数的引用。每次修改后,编译并测试。

7、删除旧函数。

8、编译测试。

三、Remove Parameter(移除参数)

函数本体不再需要某个参数。

将该参数移除。

动机

参数代表着函数所需的信息,不同的参数值有不同的意义。函数调用者必须为每一个参数操心该传什么东西进去。如果你不去掉多余参数,就是让你的每一位用户多费一份心。是很不划算的,更何况“去除参数”是非常简单的一项重构。

做法

1、检查函数签名是否被超类或子类实现过。如果是,则需要针对每份实现分别进行一下步骤。

2、声明一个新函数,名称与原函数相同,只是去掉不必要的参数。将旧函数的代码复制到新函数中。

3、编译

4、修改旧函数,令它调用新函数。

5、编译,测试

6、找出旧函数的所有被引用点,将它们全部修改为新函数的引用。每次修改后,编译并测试。

7、删除旧函数。

8、编译测试。

四、Separate Query from Modifier(将查询函数和修改函数分离)

某个函数既返回对象状态值,又修改对象状态。

建立两个不同的函数,其中一个负责查询,另一个负责修改。

动机

如果某个函数只是向你提供一个值,没有任何看到的副作用,那么这是个很有价值的东西。你可以任意调用这个函数,也可以把调用动作搬移到函数的其他地方。简而言之,需要操心的事情少多了。

明确表现出“有副作用”与“无副作用”两种函数之间的差异,是个很好的想法。下面是一条规则:任何有返回值的函数,都不应该有看得到的副作用。有些程序员甚至将此作为一条必须遵守的规则。就像对待任何东西一样,我并不绝对遵守它,不过我总是尽量遵守,而它也回报我很好的效果。

你也许已经注意到了:我使用“看得到的副作用”这种说法。有一种常见的优化办法是:将查询结果缓存到某个字段中,这么一来后续的重复查询就可以大大加快速度。虽然这种做法改变了对象的状态,但这一修改是察觉不到的,因为不论如何查询,你总是获得相同结果。

做法

1、新建一个查询函数,令它返回的值与原函数相同。

观察原函数,看它返回什么东西。如果返回的是一个临时变量,找出临时变量的位置。

2、修改原函数,令它调用查询函数,并返回获得的结果。

原函数中的每一个return句都应该像这样:return newQuery(),而不应该返回其他东西。

如果调用者将返回值赋给了一个临时变量,你应该能够去除这个临时变量。

3、编译、测试。

4、将调用原函数的代码改为调用查询函数。然后,在调用查询函数的那一行之前,加上对原函数的调用。每次修改后,编译并测试。

5、将原函数的返回值改为void,并删掉其他所有的return语句。

并发问题

如果你在多线程系统中工作,肯定知道这样一个重要的惯用手法:在同一个动作中完成检查和赋值。这是否和Separate Query from Modifier互相矛盾呢?两者并不矛盾,但你需要做一些额外工作。将查询动作和修改动作分开来仍然是有价值的。但你需要保留第三个函数来同时做着两件事。这个“查询-修改”函数将调用各自独立的查询函数和修改函数,并被声明为synchronized。如果查询函数和修改函数未被声明为synchronized,那么你还应该将它们的可见范围限制在包级别或private级别。这样,你就可以拥有一个安全、同步的操作,它由两个较易理解的函数组成。这两个较低层函数也可以用于其他场合。

五、Parameterize Method(令函数携带参数)

若干函数做了类似的工作, 但在函数本体中却包含了不同信息。

建立一个单一函数,以参数表达那些不同。

动机

你可能会发现这样的两个函数:它们做着类似的工作,但因少数几个值致使行为略有不同。这种情况下,你可以将这些个字分离的函数同一起来,并通过参数来处理那些情况,用以简化问题。这样的修改可以去除重复的代码,并提高灵活性,因为你可以用这个参数处理更多的情况。

做法

1、新建一个带有参数的函数,使它可以替换先前所有的重复性函数。

2、编译

3、将调用旧函数的代码改为调用新函数。

4、编译、测试。

5、对所有旧函数重复上述步骤,每次替换后,修改并测试。

也许你会发现,你无法用这种办法处理整个函数,但可以处理函数中的一部分代码。这种情况下,你应该首先将这部分代码提炼到一个独立函数中,然后再对那个提炼所得的函数使用Parameterize Method

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值