重构--重构名录

重构和测试

要正确地进行重构,前提是得有一套稳固的测试集合,以帮助开发人员发现难以避免的疏漏。

重构名录

  1. 提炼函数
    动机:如果需要花费时间浏览一段代码才能弄清它的作用,就应该将其提炼到一个函数中。以至于再浏览这个函数时,很清楚该函数的作用,不需要关心函数是如何实现的。
    做法:

    • 创建一个新函数,根据这个函数的意图来命名(以它“做什么”来命名,而不是“怎样做”命名)。
    • 将待提炼的代码从源函数复制到新建的函数中。
    • 检查提炼代码中是否引用了作用域限于源函数、在新函数中无法访问的变量。如果有,就以参数的形式传递给新函数。
    • 将源函数中被提炼的代码段替换成对目标函数的调用。
    • 测试。
  2. 内联函数
    动机:

    1. 某个函数内部代码和函数名称清晰易读,但是又重构了该函数的内部实现。
    2. 代码中有太多间接层,使得系统中的所有函数似乎只是对另一个函数的简单委托(过度的重构)。

    做法:

    • 检查函数,确定它不具有多态性。
    • 找出这个函数的所有调用点。
    • 将这个函数的所有调用点都替换成函数本体。
    • 测试。
    • 删除该函数的定义。
  3. 提炼变量
    动机:表达式有可能非常复杂而难以阅读。这种情况下,使用提取变量给表达式命名。在一个类中,最好将其提炼成方法。
    做法:

    • 确认要提炼的表达式没有副作用。
    • 声明一个不可修改的变量,复制要提炼的表达式并将该表达式的结果值给变量赋值。在一个类中声明一个函数,将表达式的值返回。
    • 用新变量取代原来的表达式。
    • 测试。
  4. 内联变量
    动机:有时候变量名并不比表达式本身更具有表现力,有时候甚至会妨碍重构附近的代码。这时候直接使用表达式更好。
    做法:

    • 检查确认变量赋值语句的右侧表达式没有副作用。
    • 如果变量没有被声明为不可修改,先将其变为不可修改,测试。
    • 找到第一处使用改变量的地方,将其替换为直接使用赋值语句的右侧表达式。
    • 测试。
    • 重复前两步,逐一替换其他所有使用改变量的地方。
    • 删除声明点和赋值语句。
    • 测试。
  5. 改变函数声明
    动机:意义不明的函数名或参数列表。
    做法:

    1. 简单做法
      • 如果要移除一个参数,需要先确定函数体内没有使用该参数。
      • 修改函数声明,使其成为你期望的状态。
      • 将旧函数声明的地方,改成新的函数声明。
      • 测试。
    2. 迁移式做法
      • 如果有必要,先对函数体内部加以重构,是后面的提炼步骤易于展开。
      • 使用提炼函数将函数体提炼成一个新函数。
      • 如果提炼出的函数需要新增参数,用前面的简单做法添加即可。
      • 测试。
      • 对旧函数使用内联函数
      • 如果新函数使用了临时的名字,再次使用改变函数声明将其改为原来的名字。
      • 测试。
  6. 封装变量
    动机:如果要更改数据,就必须同时修改所有引用该数据的代码,否则程序就不能运行。如果数据的可访问范围较小,那还不成问题。如果数据的可访问范围很大,重构难度会随之增大。封装数据能够提供一个清晰的观测点,可以由此监控数据的变化和使用情况。
    做法:

    • 创建封装函数,在其中访问和更新变量值。
    • 执行静态检查。
    • 注意修改使用该变量的代码,将其改为调用合适的封装函数。每次替换之后,执行测试。
    • 限制变量的可见性。
    • 测试。
  7. 变量改名
    动机:意义不明的变量名。使用范围越广,命名的好坏就越重要。
    做法:

    • 如果变量被广泛使用,考虑运用封装变量将其封装起来。
    • 找出所有使用该变量的代码,逐一修改。
    • 测试。
  8. 引入参数对象
    动机:一组数据总是一起出现,将数据组织成结构会让数据项之间的关系变得清晰明了。并且使用数据结构,参数列表也能缩短。
    做法:

    • 创建一个合适的数据结构,测试。
    • 使用改变函数声明给原来的函数新增一个参数,类型是新建的数据结构,测试。
    • 调整所有调用者,传入新数据结构的适当实例。每修改一处,执行测试。
    • 用新数据结构中的每项元素,逐一取代参数列表中与之对应的参数项,然后删除原来的参数,测试。
  9. 函数组合成类
    动机:如果一组函数形影不离地操作同一块数据(通常是将这块数据作为参数传递给函数),就可以组件一个类。类能明确地给这些函数提供一个共用的环境,在对象内部调用这些函数可以少传许多参数,从而简化函数调用。
    做法:

    • 运用封装记录对多个函数共用的数据记录加以封装。
    • 对于使用该记录结构的每个函数,将其移入新类中。
    • 处理该数据记录的逻辑可以用提炼函数提炼出来,并移入新类。
  10. 拆分阶段
    动机:一段代码在同时处理两件不同的事情,就可以将其拆分成各自独立的模块。
    做法:

    • 将第二阶段的代码提炼成独立的函数,测试。
    • 引入一个中转数据结构,将其作为参数添加到提炼出的新函数的参数列表中,测试。
    • 逐一检查提炼出的“第二阶段函数”的每个参数。如果某个参数被第一阶段用到,就将其移入中转数据结构,测试。
    • 对第一阶段的代码运用提炼函数,让提炼的函数返回中转数据结构。
  • 27
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值