文档章节

大话重构连载18:最常见的问题

rakshasa
 rakshasa
发布于 2014/12/27 17:27
字数 2117
阅读 6
收藏 0
使用抽取方法,虽然道理十分简单,但实际操作起来却并不是那么容易的。完成抽取方法最大的困难,就是如何处理抽取函数与原函数的数据交换。如同将一颗大树从土壤里拔出来,盘根错节的根茎,那是剪不断理还乱。当代码还没有被抽取出来之前,它们与其它程序都是在一个函数的内部,因此各个代码段可以毫无顾忌地相互交互数据。但当我们将代码从原函数中抽取出来时,抽取出来的代码与原函数中的代码就形成了一道墙,要交换的数据只能通过参数与返回值进行交互,这将给我们带来诸多麻烦。

将代码从原函数中抽取出来,放进新的函数中,首先就会显示许多的错误,即显示许多变量未定义,这就为我们分析有哪些变量需要交互提供了线索。将所有要交互的数据都写到函数的参数中,理论上是没有问题的,却不是一个好的设计。一方面,它显得非常丑陋,长长的参数列表,使程序变得很傻而难于理解;另一方面,它也留下了一个隐患:当程序发生变更时,很可能因为增加参数而改变函数的接口,这是我们不愿看到而尽量避免的。因此,在处理数据交互方面,我更愿意选择使用值对象。值对象(Value Object)就是没有任何业务,仅仅用于传递数据的简单对象。将一堆变量杂乱无章地塞进一个值对象中,不是不可以。实际上,在重构的初期,我们往往就是这样做的。但是,随着重构的深入,值对象也在逐渐优化,最终每个值对象都应当对应现实业务中的一个事物,而它所包含的变量,就是这个事物应当拥有的属性。因此,最终函数传递的参数,应当是几个值对象,以及这些值对象以外的几个变量。建议一个函数的参数不要超过六个,最好是1~4个。

另外一个比较麻烦的问题就是返回值。在Java世界,函数的返回值只能是一个。如果我们的程序需要返回2个,甚至更多时,怎么办呢?返回一个值对象,是个好的办法。但在一个函数中,传递的参数是个值对象,返回值又是另一个值对象,如果都这样设计就会出现大量的值对象,造成值对象的泛滥。将要返回的数据直接塞进参数值对象中,是我们可以采用的另一个好的方法。在Java语言中没有形参实参的区别,如果传递进去的是一个对象,在函数中将该对象的某个属性进行了修改,即使程序已经跳出了抽取函数而回到原函数,该修改也依然起效。通过原函数对该对象的访问,就实质性地实现了抽取函数返回值的功能。从另外一个角度来说,我们的函数,就是对这些值对象中数据的处理过程。这个过程就像一个摩托车生产线,就这辆摩托,你先装上一个发动机,我再安两个轮子。我们的处理过程被设计成由一系列函数,依次对某个值对象进行连续处理。这样值对象就变成一个载体,在原函数与抽取函数之间交互数据。这样,前面讨论的参数与返回值的问题将得到解决。

比如,我们的系统现在从前端提交了一个表单,我们首先通过Servlet或Action获得前端传递过来的数据,填入一个值对象中。然后该表单可能需要一系列校验,因此我们将这个值对象传递给每个校验函数中。校验函数对值对象进行一些校验,可能还会对值对象写入一些标志。接着可能会调用一些处理函数,从数据库中查询一些数据填入到该值对象中。经过一系列的校验与处理,值对象中的数据被填补完整了,最后交给持久化函数去写库。所有这些函数的调用都只需要传递这个值对象就可以了,甚至可以没有返回值,问题得到解决。

除此之外,实践抽取方法中另一个总是让我们反复思考的问题,就是那个“画红线”的问题。正如前面所说,原函数中的那些块操作,如条件语句、循环语句、try语句,都是进行抽取操作比较明显的标志。但关键问题是,这并不意味着那些块操作中所有的代码都是抽取函数的范围,我们需要考虑许多的因素。当然,最初最直观地想法是将块操作中所有的代码抽取出来。但是,在放入函数,在分析它的参数列表与返回值时,我们可能会发现问题。一些参数,如request、response等,我们并不希望作为参数直接传递进来。这时候,将抽取函数中最前面或最后面的部分代码移出该函数,放回原函数,是一个比较直观的想法。还有,当一些函数功能相似、位置并列时,后续我们可能会对它们进行相应的归并处理,因此在此时抽取函数时,可能期望能统一画线在相同的位置上。以上这些问题都是我们在重构过程中需要仔细考虑的问题。

最后我们要讨论的话题是抽取方法的命名。过去我们对方法的命名常常有些令人摸不着头脑,究其原因,一方面是程序员对这方面过于随意,而另一方面是我们所站的角度不对。我们应当站在使用者的角度命名,而不是开发者的角度。我们应该告诉使用者,调用这个方法会执行什么功能,即它的操作意图是什么。这样使用者才能正确理解,并在合理的地方使用。前例中那个getBlsj()就是一个最好的明证(详见 5.1 超级大函数):起初命名为getBlsj()就是因为站在开发人员的角度它就是获取办理时间的,如果这样命名则其他使用者只能用它来获取办理时间。然而它真实的意图是什么呢?是转换日期格式,因此将其改名为transformDate()。正因为这样的改名,其他开发者才明白可以用它转换其它类似的日期,而不仅仅是办理时间。这足见方法的命名是如此重要,我们不得不察。

此外,我给大家的建议是命名不要过于专业。对于一些专业术语,查字典去找一个连自己都不认识的英语单词,你自己都不认识,怎么能够要求你的读者认识呢!命名的目的是为了增加可读性,因此专业的英语单词无助于提高可读性,应当尽量避免,而一些约定俗成的拼音未尝不可。比如纳税人识别号,有人命名为taxpayerId或者taxpayerCode。但如果整个行业都使用nsrsbh,这样写大家都看得懂,反倒taxpayerId或者taxpayerCode显得比较突兀。再比如发票,有人查了字典,命名为invoice。Invoice可以指发票,也可以指其它各种与商品清单有关的单据,因此不准确,还不如命名为fp简单明了。

大话重构连载首页: http://fangang.iteye.com/blog/2081995
特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!

本文转载自:http://fangang.iteye.com/blog/2151567

rakshasa
粉丝 34
博文 142
码字总数 16820
作品 0
昆明
高级程序员
私信 提问
大叔推荐博客索引

以下是我的所有推荐文章,其中多半是文章系列,并且这个索引会在以后过程中进行追加,所以,各位看到的,永远都不是最新的,呵呵! 大叔推荐文章系列 DotNetCore跨平台~文章索引~永久更新(...

mcy247
2017/12/05
0
0
java 之 命令模式(大话设计模式)

命令模式,笔者一直以为当我们开发的过程中基本上很难用到,直到维护阶段或者重构阶段,我们会发现有些撤销命令和追加命令比较频繁时,自然而然就用到命令模式。 先看下类图 大话设计模式-类...

红尾巴的猪
2017/12/19
0
0
【专栏精选】实战:使用LeanCloud上传玩家分数,实现排行榜

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/zhenghongzhi6/article/details/91362256 本文节选自洪流学堂公众号技...

关尔Manic
06/10
0
0
Java重构示例

1.尽量简洁 1.1重构前 if ( flag == 1 ){ }else{ } 1.2重构后 return flag == 1; 2.使用三位运算符 2.1重构前 if ( "Male".equals(gender) ) { }else{ } 2.2重构后 return "Male".equals(gen......

动听的椰子
2016/04/08
141
0
重构的七宗罪

重构经过了十几年的发展和应用,可以说它是极限编程中程序员最爱的实践之一了,纷纷争相在项目里应用。重构工作坊、Codekata重构练习等各种 提升能力的方式也屡见不鲜,帮助程序员们去追求优...

oschina
2016/03/29
9.1K
15

没有更多内容

加载失败,请刷新页面

加载更多

Vue warn]: Computed property "activeNames" was assigned to but it has no setter.

在使用 vue,element-ui时,如下代码 <template> <el-form :model="numberValidateForm" ref="numberValidateForm"> <el-form-item> <el-tabs v-model="activeNames" @tab-cl......

牧云橙
34分钟前
6
0
重构-改善既有代码的设计-6.2内联函数

6.2内联函数 动机 本书经常以简短的函数表现动作意图,这样会使代码更清晰易读。但有时候你会遇到某些函数,其内部代码和函数名称同样清晰易读。也可能你充够了该函数的内部实现,使其内容和...

还仙
35分钟前
6
0
Less 混入

混合类似于编程语言中的函数。 Mixins 是一组CSS属性,允许我们将一个类的属性嵌套于另一个类,被嵌入的类可以看作是变量,并且包含类名作为其属性,也就是说我们可以用一个类定义样式然后把...

凌兮洛
38分钟前
6
0
频繁FGC的真凶原来是它

频繁FGC的真凶原来是它 上周排查了一个线上问题,主要现象是CPU占用过高,jvm old区占用过高,同时频繁fgc,我简单排查了下就草草收场了,但是过后我对这个问题又进行了复查,发现问题没有那...

每天晒白牙
38分钟前
6
0
简单的树形菜单如何写

业务需求 数据结构中含有图片、名称、children的树形结构,需要展示出每一级的图片名称和图片,找了些树形图的插件,都没有展示大的图片的,一般都是小图标,就自己试着写一个包含图的简单的...

tianyawhl
40分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部