达文西,你想改善代码质量的话,你要懂重构啊!
Posted 码农一天
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了达文西,你想改善代码质量的话,你要懂重构啊!相关的知识,希望对你有一定的参考价值。
达文西写了一段时间的代码,心里没底,并不知道自己的代码水平和质量处在哪个阶段,他一直说自己是刚入门的小学生。他看了很多语言基础类、框架类以及工具类的书籍,越看越觉得没有尽头。
有一天,他碰巧看到一篇文章里说,把大量时间投资在学习框架是不划算的,应该学习那些不随时间流逝让程序员受益终身的技能,比如锻炼好的编程习惯、重构代码、学习如何高效编程、设计模式以及很多事物的底层实现原理等等。
于是,达文西就买了一本《重构,改善既有代码的设计》,准确来说,他买的是一本英文+评注的版本(Refactoring: Improving the Design of Existing Code)。他想着一边学习技能还能一边学英文,多好。
这本书一共十五章。达文西一开始看得特别认真,每一行每个单词都看,看了几章之后,觉得效率太慢,于是舍弃学习英语的目的,挑重点并加快浏览速度。
第一章
一开篇直接举例子,展示了一段根据每个客户租赁的影片自动计算出租金总额、获得的积分总额并格式化输出结果。随后一步步修改这一段代码:
(1)先写几个测试用例,改动代码之后跑一下这些测试用例看看结果是否和改之前一样,如果是一样的,说明大概率没有改错。
(2)把while里循环计算单个影片所需金额的那段代码提炼出来,单独弄成一个函数。
(3)测试用例跑一下,发现数据有点出入,发现翻来是上面提炼出来的函数的返回值不小心写错了,应该是double,不小心写成了int。
(4)上面那段提炼出来的代码,因为单独成了一个函数,函数体中的一些变量名字就可以更改一下以便更好理解。
(5)甚至可以把上面提炼出来的那段代码,放在另一个合适的类中,以后需要使用的时候,直接调用这个类的这个方法就直接能获得这个影片的租赁总额。
(6)接下来把最初代码中计算积分总额的代码块也提炼成一个函数。
(7)有些是直接调用提炼出的这两个函数以获得返回值的,就不需要先把这个返回值赋值给一个变量,然后拿这个变量去计算或者拼接字符串等,而是直接在所需计算或拼接的地方直接调用函数,这样就省去一些中间临时变量。
(8)如果一些方法涉及到多个类的数据,那么就需要决定这个方法放在哪个类中被调用比较合适。
(9)因为影片有很多种类,计算的竹林总额和积分都和种类有关,如果万一以后要增加新的种类怎么办?这个时候可以考虑使用继承,父类定义方法,子类根据自己的类型重写父类的计算总额和总积分的方法,这样以后新增另一个类型,不影响之前的。其实这也是面向接口编程的思想。
就是这样实打实地告诉你为什么要重构,以及用什么方法一步步重构。
第二章
这章没有具体方法,主要是讲重构的一些基本原则和思想。
先定义一下重构,因为这本书写得很早,那时候重构的概念还很模糊。为什么应该重构?这一点我打赌你能说出一些好处,比如对自己负责,也对以后接手项目的别人负责。尽管重构会耽误些时间,但以后还是有好处,总之,你不许说它有坏处。
最重要的是什么时候开始重构?一边写代码一边重构,这一点我比较赞同。让程序员回头看自己的代码然后重构是很痛苦的一件事,只有写的时候遇到新增功能、重复代码等觉得别扭不顺畅的时候立即着手重构,这是最好的实践方法。
第三章
这是最重要的一个章节,也是应该最后再看的一个章节,名字叫做代码的坏味道。也就是说这些代码都是不太好的代码,你要是发现它们的话基本意味着要重构。这里只是列举的每一种坏味道是什么,以及可以使用哪些方法重构,这些方法就是后面连续多个章节提到的具体方法。
我们可以把一些典型坏味道的代码先列在这里,比如代码如果存在大量重复、方法体内代码行数太多、类中变量或者方法太多导致类太大、传递参数时发现参数个数太多、每次一个小变化要同时修改很多个函数以及很多处地方、函数名字不能明确传递意思、临时变量或者中间变量很多、太多复杂或者混乱以致于需要过多的注释等等情况。
第四章
主要是说建立测试对于重构的重要性。但建立测试是否有必要这个值得商榷。对于重构一个已经存在很久或者重构工作量很大的工程,测试是有必要的。但如果是一边写代码一边重构,而且大部分是重构自己之前写的代码,那么测试这一部分是可以省略的,除非时间非常充裕。
第五章
这一章节是说明接下来的第六章至第十二章,用什么方法来讲重构方法:先说这个重构叫什么名字,然后是为什么要重构,其次是重构的步骤和方法,最后是具体案例。
第六章至第十二章
这七章,讲了很多的重构方法,名字多到记到烧脑。但核心思想还是比较好理解:
(1)对于过长过大的类和方法,要拆解成多个类,提炼成多个函数。命名要直观易懂。尽量消除不必要的中间或者临时变量。
(2)方法或者字段要放在合适的类中。如果多个方法或多个类中有相似的代码、相似的方法以及相似的字段,继续提炼到一个父类方法中。
(3)数据方面的规范,比如一些数字或字符串要定义成常量后再使用,数据的封装,能用对象表示数据的尽量使用对象等。
(4)一些用于判断的逻辑表达式,可以封装成一个函数或者一个变量。
(5)函数的参数如果过多,可以考虑用一个类代替等等。
这里罗列的都是较为简单的情形,还有很多复杂的情况可以参考书中的例子。在第十二章,来了一个大汇总的例子,为了说明在真实的使用场景中,一般都是很多种重构方法一起使用。
第十三章至第十五章
第十三章说的是重构其实并不局限于改善代码领域,其实它更具有普遍意义。
第十四章说的是重构的一些工具,其实我们现在知道的,在Eclipse和Intellij IDEA中有很多现成的工具,就是Refactor中的那些,估计重命名是我们最常用的。
第十五章,是总结。
补充
首先,这确实是一本经典之作,里面提到的很多重构方法,有经验的程序员看到时估计要会心一笑。
其次,这本书的成书时间太早,java那个时候还没有枚举,所以书中部分代码的重构在现在看来可以换一种方式进行。目前,已经有修订过的第二版已经出版,感兴趣的可以购买最新版本。
对于重构,没有绝对的标准。有些方式大多数人比较认同,但有些重构方法存在一些争议,比如提炼函数时提炼到多细的颗粒度才算是好的,再比如使用父子类继承还是面向接口编程等。
最后,这是一本英文+评注的版本,比较有趣的是有一些评注直接举了评注者自己大段大段的例子,有些评注则直接提出质疑这些重构方式或者说法是否正确。
以上是关于达文西,你想改善代码质量的话,你要懂重构啊!的主要内容,如果未能解决你的问题,请参考以下文章
编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣