您好,欢迎访问三七文档
第2章重构原则2.1概念调整软件内部结构,在不改变软件行为前提下,提高其可理解性,降低修改成本。重构使软件更容易被理解和修改。可以在软件内部做很多修改,但必须对软件可观察到的外部行为造成很小变化,或不造成变化。和重构形成对比的是“性能优化”。性能优化通常不会改变组件的行为(除了执行速度),只会改变其内部结构。两者出发点不同,性能优化往往使代码较难理解,但为了得到所需性能不得不那么做。2.2重构目的1.改进软件设计如果没有重构,程序的设计会变差。当人们只为短期目的或者在完全理解整体设计之前,贸然修改代码,程序将逐渐失去自己的结构,程序员越来越难以通过阅读源码而理解原本设计。代码结构的流失是累积性的。越难看出代码所代表的设计意涵,就越难保护其中设计,于是该设计就腐败得愈快。重构很像是在整理代码,所做的就是让所有东西回到应该的位置上。经常性的重构可以帮助代码维持自己该有的形态。同样完成一件事,设计不良的程序往往需要更多代码,这常常是因为代码在不同的地方使用完全相同的语句做同样的事。因此改进设计的一个重要方向就是消除重复代码。这个动作的重要性着眼于未来。代码数量减少并不会使系统运行更快,然而会使未来可能的程序修改变得容易得多。代码愈多,就愈难正确修改,因为有更多代码需要理解。如果消除重复代码,就可以确定代码将所有事物和行为都只表述一次,这是优秀设计的根本。2.使软件更易被理解一、使别人容易理解。谓程序设计,便是与计算机交谈。编写代码告诉计算机做什么事,它的回应则是精确按照你的指示行动。除了计算机外,源码还有其他读者:数个月之后可能会有另一位程序员尝试读懂你的代码并做一些修改。二、利用重构来协助理解不熟悉的代码。看到不熟悉的代码,需试着理解它的用途。有了重构这个概念,就不会满足头脑中得到的一点体会。而是真正动手修改代码,让它更好地反映出我的理解,然后重新执行,看它是否仍然正常运作,以此检验我的理解是否正确。随著代码渐趋简洁,发现自己可以看到一些以前看不到的设计层面的东西,达到更高的理解层次。3.有助找到缺陷(bug)如果对代码进行重构,就可以深入理解代码的作为,恰到好处地把新的理解反馈回去。搞清楚程序结构的同时,也清楚了自己所做的一些假设,从这个角度来说,从而非常容易的找出缺陷。4.提高编程速度良好设计是快速软件开发的根本。拥有良好设计才可能达成快速的开发。如果没有良好设计,或许某一段时间内程序进展迅速,但恶劣的设计很快就让速度慢下来。程序员会把时间花在调试上面,无法添加新功能。修改时间愈来愈长,因为必须花愈来愈多的时间去理解系统、寻找重复代码。随著给最初程序打上一个又一个的补丁,新特性需要更多代码才能实现。这是个恶性循环。2.3何时重构1.添加功能时最常见的重构时机就是想给软件添加新特性的时候。这些代码可能是别人写的,也可能是自己写的。无论何时只要想理解代码所做的事,就会问自己:是否能对这段代码进行重构,使我能更快理解它。之所以这么做,部分原因是为了下次再看这段代码时容易理解,但最主要的原因是:如果在前进过程中把代码结构理清,就可以从中理解更多东西。另外,现有代码的设计无法帮助轻松添加所需要的特性。如果改用某种方式来设计,添加特性会简单得多。2.修补错误时3.复审代码时重构可以帮助复审别人的代码。开始先阅读代码,得到一定程度的理解,并提出一些建议。一旦想到一些点子,就会考虑是否可以通过重构立即轻松地实现它们。这样可以把代码看得更清楚,提出更多恰当的建议。重构还可以帮助代码复审工作得到更具体的结果。不仅获得建议,而且其中许多建议能够立刻实现,从而在实践中得到比以往多得多的成就。2.4重构的难题1.数据库重构经常出问题的一个领域就是数据库,有两个原因:数据耦合。绝大多数商用程序都与它们背后的数据库表格结构紧密耦合在一起。数据迁移。即使非常小心地将系统分层,将数据库表格结构和对象模型间的依赖降至最低,但数据库表格结构的改变还是不得不迁移所有数据。在非对象数据库中,解决这个问题的办法之一就是:在对象模型和数据库模型之间插入一个分隔层,隔离两个模型各自的变化。升级某一模型时无需同时升级另一模型,只需升级上述的分隔层即可。这样的分隔层会增加系统复杂度,但会带来很大的灵活度。如果同时拥有多个数据库,或如果数据库模型较为复杂使人难以控制,那么即使不进行重构,这分隔层也很重要。对开发者而言,对象数据库既有帮助也有妨碍。某些面向对象数据库提供不同版本的对象之间的自动迁移功能,这减少了数据迁移时的工作量,但还是会损失一定时间。如果各数据库之间的数据迁移并非自动进行,就必须自行完成迁移工作,这种情况下必须更加注意数据结构变化。数据尚未被转移前先运用访问函数造成数据已经转移的假象。一旦确定数据应该在何处时,就可以一次性地将数据迁移过去。这时惟一需要修改的只有访问函数,从而降低错误风险。2.修改接口如果重构手法改变了已发布接口,必须同时维护新旧两个接口,直到所有用户都有时间对这个变化做出反应。尽量让旧接口调用新接口。当要修改某个函数名称时,留下旧函数,让它调用新函数。千万不要拷贝函数实现码,那会陷入重复代码中难以自拔。还应该使用Java提供的“反对”设施,将旧接口标记为deprecated。这么一来调用者就会注意到它。2.5重构与设计两个观点:•把设计看作软件开发的关键环节,而把编程看作只是机械式的低级劳动。•重构可以成为“预先设计”的替代品,根本不必做任何设计,只管按照最初想法开始编码,让代码有效运作,然后再将它重构成型重构改变了预先设计的角色。如果没有重构,就必须保证“预先设计”正确无误,这个压力太大。这意味如果将来需要对原始设计做任何修改,代价都将非常高昂。因此需要把更多时间和精力放在预先设计上,以避免日后修改。如果选择重构,问题的重点就转变了。仍需做预先设计,但是不必一定找出正确的解决方案。此刻只要得到一个足够合理的解决方案就够了。因为我们知道,在实现这个初始解决方案的时候,对问题的理解也会逐渐加深,可能会察觉最佳解决方案和当初设想的有些不同。只要有重构,就不成问题,因为重构让日后的修改成本不再高昂。2.6重构与性能•时间预算法通常只用于性能要求极高的实时系统。分解设计时要做好预算,给每个组件预先分配一定资源,包括时间和执行轨跡。每个组件绝对不能超出自己的预算,就算拥有可在不同组件之间调度预配时间的机制也不行。这种方法高度重视性能,对于心律调节器一类的系统是必须的,因为在这样的系统中迟来的数据就是错误的数据。但对其他类系统(例如经常开发的企业信息系统)而言,不必如此追求高性能。编写快速软件方法:首先写出可调软件,然后调整它以求获得足够速度。•持续关切法要求任何程序员在任何时间做任何事时,都要设法保持系统的高性能。这种方式很常见,感觉上很有吸引力,但通常不会起太大作用。任何修改如果是为了提高性能,通常会使程序难以维护,因而减缓开发速度。如果最终得到的软件的确更快了,那么这点损失尚有所值,可惜通常事与愿违,因为性能改善一旦被分散到程序各角落,每次改善都只不过是从对程序行为的一个狭隘视角出发。•利用统计数据据统计,代码中只有10%需要优化。在性能优化阶段中,首先运行一个量测工具监控程序,找出程序中哪些地方大量消耗时间和空间。这样就可以找出性能热点所在的一小段代码。然后集中关切这些点,并使用前述持续关切法中的优化手段来优化它们。由于把注意力都集中在少量点上,较少的工作量便可显现较好的成果。
本文标题:第2章-重构原则
链接地址:https://www.777doc.com/doc-5002201 .html