天天看点

重构笔记(一)——坏味道

第一章: 重构第一个案例

1. 重构第一步:建立一组可靠的测试环境

2. 提取出函数: 选中区域,点击Extract method(可修改参数名,函数名,扔出异常,加入comment,),运行测试判断是否正确. 阅读代码时,我经常重构.这样随着对程序的理解逐渐加深,也会不断把这些理解嵌入代码中.

3. 判断子函数的参数,将参数只属于特定类的子函数复制到对应类,编译并测试

4. 移出临时变量,编译并测试

5. 对于循环增加的临时变量,extract method并将循环移入.重构时不必担心性能,优化时才需要担心.优化时可通过插入stopwatch确定性能点,从而优化

6. 对于预测变化时的重构,尽量减少受到影响的范围

7. 对于switch语句,使用state pattern重构,是为了需求变化时更加容易

第二章: 重构原则

修改功能和重构,无论何时都应该清楚自己戴的是哪一顶帽子.

重构之前:代码必须在大部分情况下能正常运作

何时重构

添加功能,修改错误

何时不该重构

项目进入最后期限

性能

程序设计时,不需要关注性能,当编写完成后,使用测试软件找到hot pot,然后针对该区域进行优化

重构的难题

数据库

       通过在对象模型和数据库模型之间插入一个隔离层

修改接口

       如果该接口使用者无法控制,在接口改变时,保留原接口,设为depreciated。旧接口调用新接口实现。

第三章: 代码的坏味道

重复代码:

同一类中的两个函数:extract method

同一类的两个子类:extract method, pullup method, form template method

做同一件事的两个不同算法:使用一个清晰的取代其他,substitute algorithm

两个不相干的类:将共有代码extract class ,另一个类调用,也需要从语义上判断该函数是否属于一个类

large function:

让function容易理解的关键是起一个好名字

每当需要以注释解释函数时,就将要说明的东西写入一个函数并以函数的用途来命名它,哪怕替换后的函数比原来还长,只要函数名上看出其用途,也应该毫不犹豫地这样做.

方法:

        99%的场合:Extract method

        太多的参数和临时变量: replace temp with query和introduce parameter object

        临时变量被多次复制:split temporary variable

该提炼哪些:

寻找注释. 就算只有一行代码,如果其需要注释,也应该将其提出到一个函数

条件: decompose conditional

循环:将循环和其内的代码提炼到一独立的函数

large clas

方法:

先找到彼此相关的变量(有相同前缀或后缀);提炼该变量相关的代码:extract class, move field, move method

太多参数

方法:

        参数由函数计算得到:replace parameter with method

        参数所在对象存在:preserve whole object

        参数的对象不存在:introduce parameter object

类的职责

多种原因的变化要修改一个类:extract class

一个变化修改多个类: move field,move method

依恋情节:两个类耦合

调用某一类过多的取值函数:move method

函数的部分:先extract method,再move method

一个函数用到多个类:先extract method, 将该函数放到用到数据最多的类

Data clumps:数据泥团

删除数据的一项,其他数据不再有意义

方法:

        将这些字段 Extract class;

函数参数 introduce parameter object

不必在意只用上字段的一部分字段。

Switch statements

单一函数中:replace parameter with explicit method

选择条件之一是null: introduce  null object

大量使用:1)extract method将switch提取到独立函数;2)move method到多个类;3)replace type code with subclass, replace type code with state/strategy

Parallel Inheritance Hierarchies 平行继承体系

每当为一个类增加子类,需要为另一类应增加一个子类

方法:

        让继承体系的一个子类引用另一个体系的实例;move method ,move field;就可以消除引用端的继承体系

Speculative Generality

如果函数或类的唯一用户是测试用例

类:inline class 或者collapse hierarchy

函数的某些参数:remove parameter

函数名过于抽象:rename method

Message Chains

一长串的getThis()

观察该函数具体的作用,将该函数放入消息链的正确位置

Middle Man:过度委托

某个类有一半的函数都委托给其他类

方法:

remove middle man;

              少数几个函数:inlineMethod

Incomplete Library Class:不完美的库类

修改一两个函数:Introduce Forign Method

增加一大堆行为:Introduce Local Extension

Data Class

除了get set 什么也不干

找到调用处,move method; 对不提供修改的字段 remove set method;后期可用hide method隐藏get和set

Comments

说明参数规格: introduce assertion

合理的注释:将来的打算,为什么要这么做

第四章构筑测试体系

写程序最花时间的是调试错误,找出错误比较费时,改正错误是很快的

作用:

       描写该功能如何使用

       集中于接口而非实现