重构:对软件内部结构的一种调整,目的是再不改变软件的可观察行为的前提下,提高其可理解性,降低其修改成本。
两顶帽子
添加新功能 添加新功能时不应该修改既有代码,只管添加新功能,通过测试
重构 重构时你就不能再添加功能,只管改进程序结构,此时你不应该添加任何测试,只在绝对必要(用以处理接口变化)时才修改测试
为何重构
何时重构
- 三次法则:
- 第一次做某件事时只管去做;第二次做类似的事会产生反感第三次再做类似的事,你就应该重构。(事不过三,三则重构)
- 添加功能时重构
- 修补错误时重构
重构的难题
- 数据库重构
- 修改接口
- 让旧接口调用新接口,当你要修改某个函数的名称时请留下旧函数,让它调用新函数 。千万不要复制函数实现,那会让你陷入重复代码的泥淖中难以自拔。你还应该使用java中depreciation注解,将旧接口标记为
@deprecated
。
- 让旧接口调用新接口,当你要修改某个函数的名称时请留下旧函数,让它调用新函数 。千万不要复制函数实现,那会让你陷入重复代码的泥淖中难以自拔。你还应该使用java中depreciation注解,将旧接口标记为
- 难以通过重构手法完成设计的改动
- 先想像重构的情况。考虑选设计方案时,我会问自己:将某个设计重构为另一个设计的难度又多大?看上去很简单,我就不必太担心选择是否得当,于是我就会选择最简单的设计,哪怕他不能覆盖所有潜在的需求也没关系,但如果预先看不到简单的重构办法,我就会在设计上投入更多的力气。
- 何时不该重构
现有代码根本不能正常运作。重构之前,代码必须起码能够在大部分情况下正常运作 如果项目已近最后的期限,你也应该避免重构,如果项目已经非常接近最后期限,你不应该再分心于重构,因为已经没有时间了。重构能够提高生产力如果最后你没有足够时间,通常就表示你其实早该进行重构。
重构与设计
- 如果选择重构,问题的重点就改变了,你仍然做预先设计,但是不必一定找出正确的解决方案,此刻的你只需要得到一个足够合理的解决方案就够了。
- 有了重构,你就可以通过一条不同的途径来应付变化带来的风险。你仍旧需要思考潜在的变化,仍旧需要考虑灵活的解决方案。但是你不必再主意实现这些解决方案而是应该问问自己:"把一个简单的解决方案重构成这个灵活的方案又多大难度?"如果答案是“相当容易”,那么就只需要实现目前的简单方案就行了。
间接层和重构(间接层的价值)
- 允许逻辑共享
- 比如说一个子函数再两个不同的地点被调用,或超类中的某个函数被所有子类共享
- 分开解释意图和实现
- 你可以选择每个类和函数的名字,这给你一个解释自己意图的机会。类或函数内部则解释实现了这个意图的做法。如果类和函数内部又以更小单元的意图来编写,你所写的代码就可以描述其结构中的大部分重要信息
- 隔离变化
- 很可能我在两个不同的地点使用同一对象,其中一个地点我想改变对象行为,但如果修改了它,我就要冒同时影响两处的风险。为此我做出一个子类,并在需要修改出引用这个子类。现在,我可以修改这个子类而不必承担午一中影响另一处的风险。
- 封装条件逻辑
- 对象有一种奇妙的消息机制:多态消息,可以灵活而清晰地表达条件逻辑。将条件逻辑转化为消息形式,往往能降低代码的重复,增加清晰度并提高弹性。