您的位置:首页 > 编程语言

重构-改善既有代码的设计精华摘录

2016-11-18 09:25 190 查看
《重构-改善既有代码的设计》对于程序开发者来说是一本好书,其中重构的思想对我们改善程序代码的质量很有帮助,除此之外书中还有很多中肯的编程建议,非常感谢作者和重构课题相关科研人员的慷慨馈赠,也希望大家能认真对待这篇文章。

第1章 重构,第一个案例

1、差劲的系统是很难修改的,因为很难找到修改点。如果很难找到修改点,程序员就可能犯错,从而引入bug。

2、你心里牢牢记着那句古老的工程谚语:“如果它没坏,就不要动它。”这个程序也许还没坏掉,但它造成了伤害。它让你生活比较难过,因为你发现很难完成客户所需的修改。这时候,重构技术就该隆重登场了。

3、测试过程中很重要的一部分,就是测试程序对于结果的报告方式。它们要么说“OK”,表示所有新字符串都和参考字符串一样,要么就列出失败清单,显示问题字符串出现的行号。这些测试都能够自我检验。是的,你必须让测试有能力自我检验,否则就得耗费大把时间来回对比,这会降低你的开发速度。

4、任何一个傻瓜都能写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优秀的程序员。

5、代码应该表现自己的目的,这一点很重要。阅读代码的时候我经常进行重构,这样随着对程序的理解逐渐加深,我也就不断地把这些理解嵌入到代码中和,这么一来才不会遗忘我曾经理解的东西。

6、绝大多数情况下,函数应该放在他所使用的数据的所属对象内。

7、任何不会被修改的变量都可以被我当成参数传入新的函数,至于会被修改的变量就要格外小心。如果只有一个变量会被修改,我可以把它当做返回值。

待解决问题:

Replace Temp with Query是一种很好的去除临时变量的方法,不过去除临时变量也需付出性能上的代价,例如本例的费用就被计算了两次。但是很容易在Rental类中被优化。如何进行优化呢?

第2章 重构的原则

1、重构定义扩展

首先,重构的目的是使软件更容易被理解和修改。与之形成对比的是性能优化,和重构一样,性能优化通常不会改变组件的行为(除了执行速度),只会改变其内部结构。但是两者的出发点不同:性能优化往往使代码较难理解,但是为了得到所需的性能你不得不那么做。

其次,重构不会改变软件可观察的行为——重构之后软件功能一如既往。任何用户,不论是最终用户或其他程序员,都不知道已经有东西发生了变化。

2、完全相同的一件事,设计不良的程序往往需要更多的代码,这常常是因为代码在不同的地方使用完全相同的语句做同样的事,你在这做了点修改,系统却不如期那样工作,是因为你没有修改另一处——那的代码做着几乎完全一样的事情,只是所处的环境略有不同。如果消除重复代码,你就可以确定所有事物和行为在代码中只表述一次,这正是优秀设计的根本。因此改进设计的一个重要方向就是消除重复代码。

3、重构不是一件应该特别拨出时间做的事情,重构应该随时地进行。你不应该为重构而重构,你之所以重构,是因为你想做别的什么事,而重构可以帮你把那事做好。

4、事不过三,三则重构。

5、重构可以帮助自己理解不熟悉的代码和软件。

6、是什么让程序如此难以相与?眼下我能想起下述四个原因,它们是:

难以阅读的程序,难以修改;

逻辑重复的程序,难以修改;

添加新行为时需要修改已有的代码,难以修改;

带有复杂条件逻辑的程序,难以修改。

因此,我们希望程序:

(1)容易阅读

(2)所有逻辑都只在唯一地点指定

(3)新的改动不会危及现有行为

(4)尽可能简单表达条件逻辑。

7、如果重构手法改变了已发布接口,你必须同时维护新旧两个接口,让旧接口调用新接口,直到所有用户都有时间对这个变化做出反应。当你要修改某个函数名称时,请留下旧函数,让他调用新函数。千万不要复制函数实现,那会让你陷入重复代码的泥淖中难以自拔。

8、虽然重构可能使软件运行更慢,但它也使软件的性能更容易优化。除了对性能有严格要求的实时系统,其他任何情况下“编写高性能软件”的秘密就是:首先写出可调的软件,然后调整它以求获得足够的速度。

9、关于性能,一件很有趣的事情就是:如果你对大多数程序进行分析,就会发现它把大半时间都耗费在一小半代码身上。如果你一视同仁地优化所有代码,90%的优化工作都是白费劲的,因为你的优化很少执行。所以在性能优化期间,你首先应该用一个度量工具来监控程序的运行,让他告诉你程序中哪些地方大量耗费时间和空间。这样你就可以找出性能热点所在的一小段代码,并使用持续关注法中的优化手段来优化他们。由于你把注意力都集中在热点上,较少的工作便可显现较好的成果。

第3章 代码的坏味道

1、每当感觉需要用注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。我们可以对一组甚至短短一行代码做这件事。哪怕替换后的函数调用动作比函数自身还长,只要函数名称能够解释其用途,我们也该毫不犹豫地这么做。关键不在于函数的长度,而在于函数“做什么”和“如何做”之间的语义距离。

2、条件表达式和循环常常也是提炼的信号,你可以使用Decompose Conditional处理条件表达式。至于循环,你应该将循环和其内部代码提炼到一个独立函数中。

3、如果向已有的对象发出一条请求就可以取代一个参数,那么你应该激活重构手法Replace Parameter with Method。在这里,“已有的对象”可能是函数所属类内的一个字段,也可能是另一个参数。你还可以运用Preserve Whole Object将来自同一对象的一堆数据收集起来,并以该对象替换他们。如果某些数据缺乏合理的对象归属,可使用Introduce Parameter Object为他们制造一个“参数对象”。

4、Divergent Change是指“一个类受多种变化的影响”,Shotgun Surgery是指“一种变化引发多个类相应修改”。这两种情况下你都会希望整理代码,使“外界变化”与“需要修改的类”趋于一一对应。

5、对象技术的全部要点在于:这是一种“将数据和对数据的操作行为包装在一起”的技术,有一种经典的气味是:函数对某个类的兴趣高于对自己所处的类的兴趣。当然一个函数往往会用到几个类的功能,那么他究竟该被置于何处呢?我们的原则是:判断哪个类拥有最多被此函数使用的数据,然后就把这个函数和那些数据放在一起。最根本的原则是:将总是一起变化的东西放在一起,数据和引用这些数据的行为总是一起变化的。

6、Data Class(数据实体类)就像小孩子。作为一个起点很好,但若要让他们像成熟的对象那样参与整个系统的工作,他们就必须承担一定责任。

第4章 构筑测试体系

1、一旦功能测试者或最终用户找到软件中的bug,要除掉它至少需要做两件事。当然你必须修改代码,才得以排除错误,但你还应该添加一个单元测试,用来暴露这个bug。

2、测试的要诀是:测试你担心出错的部分,这样你就能从测试工作中得到最大利益。

3、考虑可能出错的边界条件,把测试火力集中在那。“寻找边界条件”也包括寻找特殊的、可能导致失败的情况。对于文件相关的测试,空文件是一个不错的边界条件。

第5章 重构列表

1、重构的基本技巧——小步前进、频繁测试已经得到多年的实践检验,特别是在Smalltalk社群中。所以,我敢保证,重构的这些基础思想是非常可靠的。

2、许多重构手法都涉及向系统引入设计模式,正如GoF的经典著作所说:“设计模式……为重构行为提供了目标。”模式和重构之间有着一种与生俱来的关系。模式是你希望达到的目标,重构则是到达之路。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息