大话重构连载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

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

posted @ 2014-10-29 09:40  充满诗意的联盟  阅读(986)  评论(0编辑  收藏  举报