引用
任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码才是优秀的程序员。
一、什么是重构?
重构是在不改变软件
可观察行为的前提下
改善其内部结构。
重构是一种经千锤百炼形成的有条不紊的程序整理
方法,可以最大限度地减少整理过程中引入错误的几率。
本质上说,重构就是在代码写好之后改进它的设计。
如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构那个程序,使特性的添加比较容易进行,然后再添加特性。
1. 重构的第一步
每当我们要进行重构的时候,第一个步骤永远相同:为即将修改的代码建立一组
可靠的测试环境(如果没有的话)。
好的测试是重构的根本。
2. 使用重构策略
分割大方法为
小方法,把小方法提取到它应该存在的地方(类或对象中)。
“单一职责原则”“一个类只应有一个变化的原因”等等都在说明
"小"而美。
二、 重构原则
首先:重构的目的是使软件更容易被理解和修改。
其次:重构不会改变可观察的行为。
Kent beck有个“两顶帽子”比喻。使用重构技术开发软件时,你把自己的时间分配给两种截然不同的行为:
添加新功能,以及重构。添加新功能时,不应该修改既有代码,只管添加新功能。通过测试,可以衡量自己的工作进度。重构时,不能再添加功能,只管改进程序结构。此时,不应该添加任何测试,只在绝对必要时才修改测试。
软件开发过程中,可能会经常变换帽子,交叉进行。
2.1 为何重构
1. 重构改进软件设计
如果没有重构,程序的设计会
逐渐腐 败变质。当人们只为短期目的,或是在完全理解整体设计之前,就贸然修改代码,程序将逐渐失去自己的结构,程序员愈来愈难通过阅读源码而理解原来的设计。重构很像是在整理代码,你所做的就是让所有东西回到应处的位置上。
代码结构的流失是累积性的。愈难看出代码所代表的设计意图,就愈难保护其中设计,于是该设计就腐 败得愈快。经常性的重构可以帮助代码维持自己该有的形态 。
完成同样一件事,设计不良的程序往往需要更多代码,这常常是因为代码在不同的地方使用完全相同的语句做同样的事。因此改进设计的一个重要方向就是
消除重复代码。这个动作的重要性在于方便未来的修改。代码量减少并不会使系统运行更快,因为这对程序的运行轨迹几乎没有任何明显影响。然而代码量减少将使未来可能的程序修改动作容易得多。代码愈多,正确的修改就愈困难,因为有更多代码需要理解。你在这儿做了点修改,系统却不如预期那样工作 ,是因为你没有修改另一处,那儿的代码做着几乎完全一样的事情,只是所处环境略有不同。如果消除重复代码,你就可以确定所有事物和行为在代码中只表述一次,这正是优秀设计的根本。
重复是万恶之源。
2. 重构使软件更容易理解
所谓程序设计,很大程度上就是与计算机交谈:你编写代码告诉计算机做什么事,它的响应则是精确按照你的指示行动。你得及时填补"想要它做什么"和"告诉它做什么"之间的缝隙.这种编程模式的核心就是"准确说出我所要的"。除了计算机外 ,你的源码还有其他读者:几个月之后可能会有另一位程序员尝试读懂你的代码并做一些修改.我们很容易忘记这第二位读者,但他才是最重要的。计算机是否多花了几个小时来编译,又有什么关系呢?如果一个程序员花费一周时间来修改某段代码,那才要命呢,如果他理解了你的代码,这个修改原本只需一小时。
软件的维护成本远大于初次开发成本。重构可以减少成本。
3. 重构帮助找到bug
4. 重构帮助提高编程速度
良好设计是维持软件开及速度的根本。重构可以帮助你更快速地开发软件,因为它阻止系统腐 败变质,它甚至还可以提高设计质量.
2.2 何时重构
三次法则:
引用
DonRoberts给了一条准则:第一次做某件事时只管去做:第二次做类似的事会产生反感 ,但无论如何还是可以去做 :第三次再做类似的事,你就应该重构.
1. 添加功能时重构
最常见的重构时机就是我想给软件添加新特性的时候.此时,重构的直接原因往往是为了帮助我理解需要修改的代码一这些代码可能是别人写的,也可能是自己写的。无论何时,只要我想理解代码所做的事, 我就会问自己 :是否能对这段代码进行重构,使我能更快地理解它。然后我就会重构。之所以这么做,部分原因是为了让我下次再看这段代码时容易理解,但最主要的原因是:如果在前进过程中把代码结构理清,我就可以从中理解更多东西 .
在这里,重构的另一个原动力是 : 代码的设计无法帮助我轻松添加我所需要的特性。我看着设计,然后对自己说"如果用某种方式来设计, 添加特性会简单得多."
这种情况下我不会因为自己过去的错误而懊恼一一我
用重构来弥补它。之所以这么做,部分原因是为了让未来增加新特性时能够更轻松一些,但最主要的原因还是: 我发现这是最快捷的途径。 重构是一个快速流畅的过程,
一旦完成重构,新特性的添加就会更快速、更流畅。
2. 修补错误时重构
调试过程中运用重构,多半是为了让代码更具可读性。 当我看着代码并努力理解它的时候,我用重构帮助加深自己的理解。我发现以这种程序来处理代码,常常能够帮助我找出bug.
3. 复审代码时重构(code review)
很多公司都会做常规的代码复审,因为这种活动可以改善开发状况.这种活动有助于在开发团队中传播知识,也有助于让较有经验的开发者把知识传递给比较欠缺经验的人,并帮助更多人理解大型软件系统中的更多部分。代码复审对于编写清晰代码也很重要。我的代码也许对我 自己来说很清晰,对他人则不然 。这是无法避免的,因为要让开发者设身处地为那些不熟悉自己所做所为的人着想,实在太困难了。代码复审也让更多人有机会提出有用的建议, 毕竟我在一个星期之内能够想出的好点子很有限.如果能得到别人的帮助,我的生活会滋润得多 ,所以我总是期待更多复审.
2.3 重构与设计
重构肩负一项特殊使命:它和设计彼此互补。初学编程的时候,我埋头就写程序,浑浑噩噩地进行开发。然而很快我便发现,事先做好设计可以让我节省返工的高昂成本。于是我很快加强这种"预先设计"风格。许多人都把设计看做软件开发的关键环节,而把编程看做只是机械式的低级劳动。他们认为设计就像画工程图而编码就像施工。但是你要知道,软件和机器有着很大的差异:
软件的可塑性更强,而且完全是思想产品。正如 Alistair Cockburn所说: "有了设计,我可以思考得更快,但是其中充满小漏洞。"
有一种观点认为:重构可以取代预先设计。这意思是你根本不必做任何设计,只管按照最初想法开始编码,让代码有效运作,然后再将它重构成型。事实上这种 办法真的可行。我的确看过有入这么傲,最后获得设计良好的软件。极限编程 [Beck,XP]的支持者极力提倡这种办法。
尽管如上所言,只运用重构也能收到效果,但这并不是最有效的途径。是的,
就连极限编程的爱好者们也会进行预先设计。他们会使用 CRC卡或类似的东西来检 验各种不同想法,然后才得到第一个可被接受的解决方案,然后才能开始编码,然后才能重构。关键在于:重构改变了预先设计的角色。如果没有重构 ,你就必须保证预先做出的设计正确无误,这个压力太大了。这意味如果将来需要对原始设计做任何修改,代价都将非常高昂。因此你需要把更多时间和精力放在预先设计上,以避免日后修改。
如果你选择重构,问题的重点就转变了。你仍然做预先设计,但是不必一定找出正确的解决方案。此刻的你只需要得到一个足够合理的解决方案就够了。你很肯定地知道,在实现这个初始解决方案的时候,你对问题的理解也会逐渐加深,你可能会察觉最佳解决方案和你当初设想的有些不同。只要有重构这把利器在手,就不成问题,因为重构让日后的修改成本不再高昂。
这种转变导致一个重要结果:
软件设计向简化前进了一大步。过去未曾运用重 构时,我总是力求得到灵活的解决方案。任何一个需求都让我提心吊胆地猜疑: 在系统的有生之年,这个需求会导致怎样的变化?由于变更设计的代价非常高昂 ,所以我希望建造 一个足够灵活、 足够牢靠的解决方案,希望它能承受我所能预见的所有需求变化。问题在于要建造一个灵活的解决方案,所需的成本难以估算。灵活的解决方案比简单的解决方案复杂许多,所以最终得到的软件通常也会更难维护一一 虽然它在我预先设想的方向上的确是更加灵活。就算幸运地走在预先设想的方向上, 你也必须理解如何修改设计。如果变化只出现在一两个地方,那不算大问题。然而变化其实可能出现在系统各处.如果在所有可能的变化出现地点都建 立起灵活性 ,整个系统的复杂度和维护难度都会大大提高。 当然,如果最后发现所有这 些灵活性 都毫无必要,这才是最大的失败 .你知道,
这其中肯定有些灵活性的确派不 上用场,但你却无法预测到底是哪些派不上用场。为了获得自 己想要的灵活性,你不得不加入比实际需要更多的灵活性.
有了重构,你就可以通过一条不同的途径来应付变化带来的风险.你仍需要思考潜在的变化,仍旧需要考虑灵活的解决方案。但是你不必再逐一实现这些解决方案,而是应该问问自己"把 一个简单的解决方案重构成这个灵活的方案有多大难度? "如果答案是"相当容易" (大多数时候都如此).那么你就只需实现目前的简单方案就行了.
重构可以带来更简单的设计,同时又不损失灵活性,这也降低了设计过程的难度,减轻了设计阻力。一旦对重构带来的简单性有更多感受,你甚至可以不必再预先思考前述所谓的灵活方案,一旦简要它,你总有足够的信心去重构。是的,当下只管建 造可运行的最简化系统,至于灵活而复杂的设计,多数时候你都不会需要它。
参考:
《重构-改善既有代码的设计》 Martin Fowler著
分享到:
相关推荐
1.信息学奥赛骗分导论 2.数之理 3.数学奥林匹克中的应试技巧 本文以竞赛心态的调整为开端,以常数时间优化为基础,以数学分析与猜想为指导思想, 以非完美算法为主要策略,以搜索为最后的万能策略,讲述信息学竞赛2...
- 视图可以简化复杂的查询,隐藏敏感信息,并允许对原始数据进行逻辑重构。 9. **第十章 函数依赖**: - 描述了属性之间的依赖关系,是数据库设计中重要的理论基础。 - 函数依赖的推理规则,如 Armstrong 定理,...
1. **需求分析**:这是软件开发的起始阶段,需要理解用户的需求并将其转化为可操作的规格说明。报告可能包含对需求收集方法、用例图、领域模型的讨论,以及如何编写需求文档。 2. **系统设计**:这部分可能涵盖模块...
它利用微弱的电流刺激物体表面,并记录由此产生的电压变化,然后通过复杂的数学算法重构内部图像。以下是EIT算法导论中可能涉及的一些关键知识点: 1. **基本原理**:EIT的基本工作原理基于电磁学,特别是欧姆定律...
本书详细介绍了信号处理的基础理论和实践应用,包括信号的采样与重构、离散时间系统的特性、滤波器设计、卷积运算以及量化过程等关键概念。作者Sophocles J.Orfanidis是Rutgers University电子与计算机工程系的教授...
由于错误和不连贯的段落,完整的知识体系可能无法重构,但我会尽力构建一个相关知识点的框架。 从给出的文件信息中,我们可以确定该文档是关于《算法导论》这本书的一个习题解答集。这本书由Cormen、Leiserson和...
以下将尝试重构和总结相关的知识点: ### 计算机硬件基础 - 计算机硬件指的是构成计算机的实体机械部件。例如,硬件可以包括CPU、内存、硬盘驱动器、显卡等。这些硬件组件是计算机得以执行各种任务的基础。 ### ...
项目重构不仅在教学内容上进行了调整,而且在教学方法上也进行了创新,如表1所示。 教学实施的整体设计意图在于通过教学改革使学生能够从理论认知到技能强化,系统地掌握智慧农业的应用与关键技术。通过智慧农业...
1. 课程前期知识储备多、研究性强,但对前沿知识探索较少。这可能意味着课程内容过于陈旧,缺乏与最新技术发展的对接,导致学生无法及时获取前沿知识。针对这一问题,教学改革需要融入更多与时俱进的元素,调整教学...
对于初学者来说,书中会详细解释如何构造不同类型的小波,如Haar小波、Daubechies小波和Morlet小波等,并通过实例演示如何进行小波分解和重构。此外,书中还会介绍如何利用小波分析解决实际问题,例如信号去噪、边缘...
【机器人学导论】是关于机器人技术的综合理论学习,主要涵盖了机器人学的多个核心领域。以下是根据提供的复习试题及参考答案所提炼出的关键知识点: **名词解释:** 1. **拉格朗日运动方程式** - 描述物体动力学的...
1. **系统建模**:电力系统包括发电机、变压器、线路、负荷等多种设备,MATLAB可以用于构建这些设备的数学模型,以便进行稳态和动态分析。例如,使用SIMULINK模块库,可以构建电力系统的仿真模型。 2. **潮流计算**...
同时,不断地练习和重构代码,有助于培养解决问题和优化算法的能力。 总的来说,这个压缩包提供的《算法导论》源代码是一个宝贵的资源,它不仅提供了理论知识的实际应用,还为学习者提供了一个动手实践的机会,有助...
【工业工程导论】 工业工程(Industrial Engineering,简称IE)是一门综合性极强的工程类科学技术,它将工程技术与管理科学紧密结合,旨在提高生产效率、降低成本、保证质量和安全,从而获得多方面的综合效益。IE的...
4. **小波系数**:通过将数据与小波函数进行卷积得到的小波系数,反映了信号在特定尺度和位置上的能量分布,可用于信号的分解和重构。 小波分析的主要应用: 1. **信号去噪**:小波系数能够揭示信号的局部特征,...
【工业工程导论__生产过程优化】主要探讨了企业如何通过优化生产流程来提升效率、降低成本,以适应社会需求和市场竞争。生产过程优化是企业生产管理的关键任务,它旨在实现人与机械、资源配置和社会需求的最佳结合,...
### 数据科学导论实验一:爬虫应用与数据分析全流程解析 #### 实验概述 本实验旨在引导学生通过实践,理解并掌握数据科学的基本流程。实验选取了一个典型的场景——分析一个二手游戏交易平台的数据,来深入了解从...
采样定理是这一转换过程的关键,它规定了采样频率与信号最高频率的关系,确保信号能够无损地被重构。 接下来,课程会讲解信号的表示和分析方法,如傅立叶变换。傅立叶变换是一种将信号从时域转换到频域的工具,能...