zoukankan      html  css  js  c++  java
  • 大话重构连载17:抽取方法的实践

    说了那么多理论,我们来看看怎样使用抽取方法来重构遗留系统。如前所述,重构的过程首先是阅读程序代码,边阅读边整理程序。将功能相对独立的代码段放在一起,在前面加上注释。调整一些程序的顺序,将相关的代码尽量放在一起,但要保证程序执行的结果不会发生改变。比较典型的,将变量的定义与使用变量的代码放在一起。这个步骤比较实用,因为许多的遗留系统,其代码都有一个坏毛病,就是在程序开始时定义一大堆变量,但要弄清这些变量都用来做什么,却十分困难。边读边调整,将变量的定义逐渐迁移到使用它的代码段中,将大大提高代码可读性,你甚至会发现并简化一些变量。

    前面的工作为抽取函数做好了准备,但你不必阅读和整理完所有的代码才开始抽取。许多遗留函数的大函数非常长,你可以整理一部分,就开始着手重构。比如,把刚才分段的代码段抽取出来,形成一个独立的函数。在这里,代码段与注释,是我们决定是否需要抽取成函数的重要标志之一。

    在阅读过程中,许多长相相似的代码也是我们需要重视的重要代码。重复代码是许多遗留系统代码质量差的重要原因之一,因此提高代码复用就成为了代码优化一个重要的项目。整合大量重复的代码,将其提取到一个统一的函数中为其它各处所调用,是一个值得推荐的办法。因此,重复代码也是抽取函数的重要标志。

    除此之外,一些块操作的语句,如条件语句、循环语句、try语句,都可能成为抽取函数的标志。最典型的就是if语句,包含在if语句中间的常常是一个相对独立的功能,譬如一次重构中,原代码长得像这样:

    1     ......
    2     if (cmd != null && cmd.equals("chkCard")){
    3         //此处省略了500行
    4     } else if (cmd != null && cmd.equals("chkIc")){
    5         //此处省略了300行
    6     } else if (cmd != null && cmd.equals("chkBuffer")){
    7         //此处省略了1000行
    8     }
    9     ......

    整个这段代码有数千行之多,但整体结果就是用这样的一系列if语句组成。随后,我将每个if语句中的代码都提取出来形成了各自的函数。它们被重构成这样:

     1     ......
     2     if (cmd != null && cmd.equals("chkCard")){
     3          byte[] ret = chkCard(reader);
     4          servletOutput(res, ret);
     5     } else if (cmd != null && cmd.equals("chkIc")){
     6          byte[] ret = chkIc(reader);
     7          servletOutput(res, ret);
     8     } else if (cmd != null && cmd.equals("chkBuffer")){
     9          byte[] ret = chkBuffer(reader);
    10          servletOutput(res, ret);
    11     }
    12     ......

    这样,原来if语句中的业务操作代码,就被抽取到chkCard(), chkIc(), chkBuffer()这样的函数中了。起初我们将if语句中的所有代码都抽取出来写入这些函数中,这是十分自然而然想到的办法。但随后发现这样需要将response作为参数传递给这些函数中,这样的设计不太好。因此,将代码还原回来重新重构,将写入response的操作写入到servletOutput()中了。整个过程如图5.1所示:

    图5.1分解大函数的示例

    完成了此次重构以后,我们原来这个超级大函数由数千行代码,缩减到了百来行代码,这是一个可喜的进步,函数变得结构清晰而易于阅读。但是,被抽取出来的新函数却依然庞大,它们有的会达到一千多行,阅读依然困难。这时我们运用“抽取方法”继续分解。比如这个chkCard(),它执行的是一大堆校验,每个校验其功能都相对独立。因此,我首先调整代码顺序,将每个校验的代码都独立成一段,在前面添加相应的注释。然后使用抽取方法,将校验抽取到一个一个函数中。

    整个数千行代码的超级大函数,就这样原子裂变式地逐渐分解,最后分解成数十个函数。每个函数只有数十行代码,并通过注释标注它们的用途与参数、返回值含义。这样,一个起初难于阅读的函数,经过一系列重构,开始变得可以阅读了。是的,我们开始迈出了可喜地一步。但一个对象包含了数十个方法,这些方法被凌乱地堆砌在一起,没有层级、没有主次。最关键是,虽然每个方法都不大,但这个对象却包含数千行代码,依然显得臃肿。因此我们还需要后面的步骤继续重构。

    大话重构连载首页:http://www.cnblogs.com/mooodo/p/talkAboutRefactoringHome.html

    特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!

  • 相关阅读:
    SuperMap房产测绘成果管理平台
    SuperMap产权登记管理平台
    Android adb shell am 的用法(1)
    由浅入深谈Perl中的排序
    Android 内存监测和分析工具
    Android 网络通信
    adb server is out of date. killing...
    引导页使用ViewPager遇到OutofMemoryError的解决方案
    adb logcat 详解
    How to send mail by java mail in Android uiautomator testing?
  • 原文地址:https://www.cnblogs.com/mooodo/p/applyOfExtractMethod.html
Copyright © 2011-2022 走看看