洪流学堂,让你快人几步。
本篇内容来自洪流读书会精选内容。
上一次我们解读了前6种代码需要被重构时的迹象,今天我们将继续解读剩下的16种。
选择在何处重构
霰弹式修改
第七种,霰弹式修改。
霰弹式修改类似于发散式变化,但又恰恰相反。如果每遇到某种变化,你都必须在许多不同的类内做出许多小修改,你所面临的问题就是霰弹式修改。如果需要修改的代码散布四处,你不但很难找到它们,也很容易错过某个重要的修改。
面对霰弹式修改,一个常用的策略就是使用与内联相关的重构,把本不该分散的逻辑拽回一处。完成内联之后,可能会出现长函数或者过大的类,不过你总可以用与提炼相关的重构手法将其拆解成更合理的小块。
依恋情结
第八种,遇到腻腻歪歪的依恋情结。
所谓模块化,就是力求将代码分出区域,最大化区域内部的交互、最小化跨区域的交互。但有时你会发现,一个函数跟另一个模块中的函数或者数据交流格外频繁,远胜于在自己所处模块内部的交流,这就是依恋情结的典型情况。无数次经验里,我们看到某个函数为了计算某个值,从另一个对象那儿调用几乎半打的取值函数。疗法显而易见:这个函数想跟这个数据待在一起,那就使用搬移函数把它移过去。有时候,函数中只有一部分受这种依恋之苦,这时候应该使用提炼函数把这一部分提炼到独立的函数中,再使用搬移函数带它去它的梦想家园。
数据泥团
第九种,遭遇数据泥团。
数据项就像小孩子,喜欢成群结队地待在一块儿。你常常可以在很多地方看到相同的三四项数据:两个类中相同的字段、许多函数签名中相同的参数。这些总是会绑在一起出现的数据应该拥有属于它们自己的对象。我们处理的方法是先找出这些数据以字段形式出现的地方,运用提炼类将它们提炼到一个独立对象中。然后将注意力转移到函数签名上,运用引入参数对象和保持对象完整为它瘦身。
我们在这里提倡新建一个类,而不是简单的记录结构,因为一旦拥有新的类,你就有机会让程序散发出一种芳香。得到新的类以后,你就可以着手寻找“依恋情结”,这可以帮你找出能够移至新类中的种种行为。这样使有用的类被创建出来,大量的重复被消除,后续开发得以加速。
重复的switch
第十种,看到重复的switch语句时。
重复的switch的问题在于:每当你想增加一个选择分支时,必须找到所有的switch,并逐一更新。多态给了我们对抗这种问题的武器,使我们得到更优雅的代码库。
循环语句
第十一种,留心看到的循环语句。
遇到难以理解的循环语句,一般我们以管道取代循环的方式帮助我们更快地看清被处理的元素以及处理它们的动作。
冗赘的元素
第十二种,发现代码中冗赘的元素时。
程序元素(如类和函数)能给代码增加结构,从而支持变化、促进复用或者哪怕只是提供更好的名字也好,但有时我们真的不需要这层额外的结构。通常只需使用内联函数和内联类,如果这个类处于一个继承体系中,可以使用折叠继承体系。
夸夸其谈的元素
第十三种,遇到夸夸其谈的元素时。
如果你的某个抽象类其实没有太大作用,请运用折叠继承体系。不必要的委托可运用内联函数和内联类去除掉。如果函数的某些参数未被用上,可以用改变函数声明去掉这些参数。
临时字段
第十四种,临时字段。
有时你会看到这样的类:其内部某个字段仅为某种特定情况而设。这样的代码让人不易理解,因为你通常认为对象在所有时候都需要它的所有字段。请使用提炼类给这个孤儿创造一个家,然后用搬移函数把所有和这些字段相关的代码都放进这个新家。
过长的消息链
第十五种,发现过长的消息链。
如果你看到用户向一个对象请求另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象……这就是消息链。在实际代码中你看到的可能是一长串的取值函数或一长串临时变量。采取这种方式,意味客户端代码将与查找过程中的导航结构紧密耦合。一旦对象间的关系发生任何变化,客户端就不得不做出相应修改。
这时候应该使用隐藏委托关系。先观察消息链最终得到的对象是用来干什么的,看看能否以提炼函数把使用该对象的代码提炼到一个独立的函数中,再运用搬移函数把这个函数推入消息链。如果还有许多客户端代码需要访问链上的其他对象,同样添加一个函数来完成此事。
中间人
第十六种,碰见不干实事的中间人时。
针对人们可能过度运用委托的情况,可以使用移除中间人,直接和真正负责对象打交道。如果这样“不干实事”的函数只有少数几个,可以运用内联函数把它们放进调用端。
内幕交易
第十七种,看见正在内幕交易的模块或类时。
软件开发者喜欢模块之间建起高墙,极其反感在模块之间大量交换数据,因为这会增加模块间的耦合。在实际情况里,一定的数据交换不可避免,但我们必须尽量减少这种情况,并把这种交换都放到明面上来。
继承常会造成密谋,因为子类对超类的了解总是超过后者的主观愿望。如果你觉得该让这个孩子独立生活了,请运用以委托取代子类或以委托取代超类的方法让它离开继承体系。
过大的类
第十八种,碰到过大的类时。
如果想利用单个类做太多事情,其内往往就会出现太多字段。一旦如此,重复代码也就接踵而至了。观察一个大类的使用者,经常能找到如何拆分类的线索。看看使用者是否只用到了这个类所有功能的一个子集,每个这样的子集都可能拆分成一个独立的类。一旦识别出一个合适的功能子集,就使用提炼类、提炼超类或是以子类取代类型码将其拆分出来。
异曲同工的类
第十九种,发现异曲同工的类时。
使用类的好处之一就在于可以替换,但只有当两个类的接口一致时,才能做这种替换。请反复运用搬移函数将某些行为移入类中,直到两者的协议一致为止。如果搬移过程中造成了重复代码,或许可运用提炼超类补偿一下。
纯数据类
第二十种,遇见纯数据类时。
所谓纯数据类是指:它们拥有一些字段,以及用于访问(读写)这些字段的函数,除此之外一无长物。可以利用封装记录将它们封装起来。对于那些不该被其它类修改的字段,请运用移除设值函数。
被拒绝的遗赠
第二十一种,需要划清界限的情况。
如果子类复用超类的行为(实现),却又不愿意支持超类的接口,应该运用以委托取代子类或者以委托取代超类彻底划清界限。
注释
第二十二种,感到需要注释自己才能被读懂时。
当你感觉需要注释时,请先尝试重构,试着让所有注释都变得多余。
如果你需要注释来解释一块代码做了什么,试试提炼函数;如果函数已经提炼出来,但还是需要注释来解释其行为,试试用改变函数声明为它改名;如果你需要注释说明某些系统的需求规格,试试引入断言。
总结
至此我们将代码需要重构时的22种迹象已经解读完毕了。
让我们回顾一下这22种迹象:它们分别是神秘命名、重复代码、过长函数、全局数据、可变数据、发散式变化、霰弹式修改、依恋情结、数据泥团、重复的switch、循环语句、冗赘的元素、夸夸其谈的元素、临时字段、过长的消息链、中间人、内幕交易、过大的类、异曲同工的类、纯数据类、被拒绝的遗赠、注释。
扩展阅读
【扩展学习】在洪流学堂公众号回复
读书会
可以阅读本系列所有文章
我是大智(vx:zhz11235),你的技术探路者,下次见!
别走!点赞,收藏哦!
好,你可以走了。