这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
前言
一年的开发了,不再是刚进来的那个菜鸟了(虽然技术上仍然感觉是),也渐渐明白了重构的重要性(阅读已有代码的痛苦),最近在阅读《重构-改善既有代码的设计》这本书籍,记录下阅读笔记。
代码重构简介
重构是什么
在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。
本质上,重构就是在代码写好之后改进它的设计。
重构的两点注意
重构的目的是使软件代码更容易被理解和修改,但是要尽量保证对软件可观察的外部行为尽量没有变化。(性能优化则与之相反,性能优化通常不会改变组件的行为,只会改变其内部结构,性能优化往往使代码较难理解,但为了性能不得不做)
重构的小技巧
-
重构尽量小步前进,运用单元测试,确保无误,降低犯错几率。
-
重构。
-
尽量去除临时变量,临时变量往往引发问题 -P45
-
最好不要在另一个对象的属性基础上运用switch语句。如果不得不使用,也应该在对象自己的数据上使用,而不是在别人的数据上使用(让对象,类之间的耦合性更小)
-
状态模式和策略模式,根据你此时的需要去认定。
重构手法
Extract Method 提取方法
Move Method 移动方法(一个类中移动到另个类中)
Replace Conditional with Polymorphism(用多态性替换条件)
Self Encapsulate Field(自我封装领域,对于赋值、取值尽量使用set、get,即使是在构造函数)
Replace Type Code with State/Strategy 用状态/策略替换类型代码
使用重构技术开发的两顶帽子
在添加新功能时,不应该修改既有代码,只管添加新功能,通过测试,衡量工作进度。
在重构时,不能添加功能,只管改进程序结果,此时不应该添加任何测试(除非发现有先前遗漏的东西),只在绝对必要(用以处理接口变化)时才修改测试。
重构原则
重构应该随时随地进行,而不是为了重构而重构。你之所以重构,是疑问你想做别的什么事,而重构可以帮助你把那些事做好。
三次法则(事不过三,三则重构)
第一次想做某件事时只管去做
第二次想做类似的事会产生反感,但无奈论如何还是可以去做。
第三次再做类似的事,你就应该重构
何时重构
添加功能时重构
重构的动力:
-
帮助自己理解修改的代码
-
代码的设计无法帮助自己轻松添加自己所需要的特性。重构时一个快速流畅的过程,一旦完成重构,新特性的添加就会更快速、更流畅
-
修补错误时重构
调试过程中运用重构,多半是为了让代码更具可读性。用重构加深理解,帮助找出bug.
如果收到一份错误报告,而不能一眼看出bug,这就是需要重构的信号
-
复审代码时重构
间接层
间接层的缺点
重构往往需要引入更多的间接层,把大对象拆成多个小对象,大函数拆成许多小函数。但你应该认清的是,间接层是一把双刃剑。每次引入一些间接层,带来的成本就是需要多管理一些东西。
间接层的价值
- 允许逻辑共享
- 分开解释意图和实现
- 隔离变化
- 封装条件逻辑
如何在重构中对待间接层:
重构一方面要引入有价值的间接层,另一方面也要移除毫无价值的“寄生间接层”。(寄生间接层:本希望能够在多个地方调用,让其表现出多态性,但是实际上只有一个地方用到)
需要重构的代码
- 难以阅读,难以修改。
- 逻辑重复,难以修改。
- 添加新的行为需要修改已有代码,难以修改。
- 带有复杂条件逻辑,难以修改。
重构目标:
- 容易阅读。
- 相同的逻辑只出现一次。
- 新的改动不会危及现有行为。
- 尽可能简单地表达条件逻辑。
重构的难题
数据库-采用分隔层解决应用程序和背后的数据库结构的紧密耦合问题
修改接口-如何修改已发布的接口
在修改函数名称时,如果函数所有调用者都在开发者的控制下,那么及时修改函数名称不会有任何问题。即使是public函数。
但是,当接口被''找不到,找到也不能修改''的代码使用时,接口的修改就成为了问题,这些接口称之为 已发布接口(publish interface)
已发布接口(比如android 系统层的jar包;公司定制系统的一些接口;多模块开发中,你无法操作其他人代码,但是他人已经调用了你发布的接口)
-
一般解决方法(保留旧接口):
让旧接口调用新接口。并将旧接口标记为 deprecated
-
如非必要,不要发布公共接口
修改接口-增加异常
如果在Java的方法,在throw字句中增加一个异常,如果用户代码不做出相应习惯,编译器就不会让他通过。
要解决这个问题:
一般可以为整个包定义一个异常基类,就像java.sql的SQLException,且确保所有public函数只在自己的throws子句中声明这个异常。如此之后,可以在包中所有所欲定义子类,而不会影响调用者,调用者永远只知道那个更具一般性的异常基类。
难以通过重构手法完成的设计改动
何时不该重构
- 当代码实在太混乱时,重构塔不如重写一个来的简单,就应该放弃重构
- 当项目已近最后期限,应该避免重构
重构与设计
重构和设计是彼此互补的。
使用重构,在设计时,仍旧需要思考潜在的变化,仍旧需要考虑灵活的解决放啊,但是不必逐一实现这些方案。只要你认为要把当前简单的方案重构为一个复杂的方案很简单,你就只需要实现目前的简单方案。
重构与性能
除性能有严格要求的实时系统,其他情况下 编写快速软件的秘诀:首先写出可调试的软件,再调整它以获得速度。