论坛首页 Java企业应用论坛

《重构》读书笔记

浏览 4408 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (4) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-05-09   最后修改:2010-08-02

Martin Fowler于2003年出版的,有些观点有些陈旧了,可取其精华,去其糟粕。

前言:
    作者介绍了重构的基本概念,以及回答了what when who的问题。

可能需要重构的方面:
    1、Duplicate Code(重复代码)
    2、Long Method(长函数)
    3、Large Class(大类)
    4、Long ParameterList(过长参数)
    5、Divergent Change(函数太集中)、Shotgun Surgey(函数太发散):更改某个需求,不要更改太多的地方。我觉得这个有点难以掌握,得根据经验来做了。
    6、Feature Envy(一个类用到了太多另个类的函数)
    7、Data Clumps(数据泥团)
    8、Primitive Obsession(基本类型偏执狂):喜欢用大堆基本类型来表达,推荐尝试用小型类
    9、Switch Statements(Switch语句):switch语句导致重复和复杂,运用多态替换switch
    10、Refused Bequest(被拒绝的馈赠):superClass尽量最小话,也就是说subClass共享superClass所有的资源,可额外制造自己的工具类。
    11、Data Class(纯粹的数据类):可能作者当时的年代没有POJO这一说法,所以作者认为一个没有“行为”的数据类是不对的,其实这点不是确定的,各有所长,也是目前争议的地方。
    12、Temporary Field(令人迷惑的临时变量):尽量让临时变量变得可读。


构筑测试体系:
    作者推荐在编码阶段就开始构造单元测试,可为每个类写main方法来测试,这个我目前觉得还点苛刻了。

重构的方法:
    1、分解大函数,把大函数里面的部分操作分解成独立的小函数。有利于复用和可读。
    2、合并小函数。这都是很博弈的过程了,视情形而行。
    3、关于临时变量,作者推荐一个临时变量只被赋值一次,这个我觉得有点苛刻。
    3、将复杂表达式的结果放入临时变量。
    4、将临时变量转为成员变量从而分解大函数。这个我也不赞成,我觉得还是“最近原则”较好,成员变量会暂用内存,且很容易使类混乱,特别是有继承关系的时候,或者尽量保持成员变量声明为private。
    5、移动函数。如果Class1中某个函数与Class2有太多的合作而形成高耦合,就需要搬动这个函数了。
    6、移动成员变量。 如果Class1中某个值域被Class2过多的应用,就需要考虑搬动这个值域了。
    7、提炼类:一个class应该是一个清楚的抽象,具有明确的责任。对于过大的类需要进行分解。
    8、Inline Class:与方法7相反,是合并一些类。
    9、增加中间层来取代类与类的关系。典型的委托模式,对外永远为一个代理接口,客户不用关心内部关系是如何变化的。
    10、Remove Middle Man:删除过多的简单中间层。可以看到,很难定义什么程度的隐藏才是最合适的,项目不同时期,这个度也是不断变化的,这个就得靠自己把握了。
    11、直接使用值域或间接使用值域。所谓直接使用就是在类中直接使用成员变量,间接使用是使用成员变量的取值/赋值方法,即getXX()/setXX()方法,作者推荐这个最好根据团队习惯来定。

    12、当行为过于庞大后,就需要分离数据成为无行为的类。POJO就是典型。

    13、使用工厂或不使用工厂。这个又是个博弈的过程,使用工厂的好处是对象可以复用,坏处是需要考虑同步问题,提高复杂度。

    14、以对象替代数组。

    15、尽量隐藏类中数据结构的细节。对外只提供操作的方法。

    16、Replace record with data class/Replace type code wiht class

    17、以值域取代子类。

    18、引入NULL对象。把无效值变为无效类。
    19、使用断言?
    20、更改函数名。我觉得最有效的重构方式。
    21、查询函数和修改函数分离。类似setXXX和getXXX。
    22、移除setXXX或使用final。变量只在初始化时赋值。
    23、隐藏函数。封装即隐藏,对外只提供接口,对内封装细节。

    24、Pull Up Field/Method,把subClass中的重复代码提升到superClass。

    25、Pull down Field/Method。

    26、以委托取代继承。某个subClass只使用接口中的一部分,或是根本不需要使用父类的数据。

 

 

现实问题:

    1、程序员不知道重构。

    2、你很快已经不在职位上了。

    3、重构是额外工作,老板付钱给你是为了编写新功能。

    4、重构可能破坏现有程序。

 

 

 

 

 


重构就是一个博弈的过程,一个寻找平衡点的过程,空间和时间的平衡点,清晰和工作量的平衡点,共性和个性的平衡点...如果没有看到实际的情况,谁也无法知道具体该怎么做,但务必保持“简约而不简单的”优良作风。

 

 

 

   发表时间:2010-05-10  
C_J 写道

    作者推荐在编码阶段就开始构造单元测试,可为每个类写main方法来测试,这个我目前觉得还点苛刻了。

作者推荐的应该不是每个类写main方法,而是用Junit之类进行单元测试。在编码阶段构造单元测试说不上苛刻吧,要是按照敏捷的要求应该是TDD,写代码前先写测试呢。
0 请登录后投票
   发表时间:2010-05-10  
楼上是正解,就是 所谓的测试驱动开发
0 请登录后投票
   发表时间:2010-05-10  
sunway00 写道
C_J 写道

    作者推荐在编码阶段就开始构造单元测试,可为每个类写main方法来测试,这个我目前觉得还点苛刻了。

作者推荐的应该不是每个类写main方法,而是用Junit之类进行单元测试。在编码阶段构造单元测试说不上苛刻吧,要是按照敏捷的要求应该是TDD,写代码前先写测试呢。


即便是这样也是苛刻
第一,没有必要为每一个类作单元测试,否则何来的覆盖率之说
第二,为重点关注类写单元测试在现在大多数公司和企业也是不太现实,愿望很美好...
0 请登录后投票
   发表时间:2010-05-10  
Joo 写道
sunway00 写道
C_J 写道

    作者推荐在编码阶段就开始构造单元测试,可为每个类写main方法来测试,这个我目前觉得还点苛刻了。

作者推荐的应该不是每个类写main方法,而是用Junit之类进行单元测试。在编码阶段构造单元测试说不上苛刻吧,要是按照敏捷的要求应该是TDD,写代码前先写测试呢。


即便是这样也是苛刻
第一,没有必要为每一个类作单元测试,否则何来的覆盖率之说
第二,为重点关注类写单元测试在现在大多数公司和企业也是不太现实,愿望很美好...

70%的分支还是基本能达的到的。
0 请登录后投票
   发表时间:2010-05-10   最后修改:2010-05-10
感觉上面的同学开始离题了,讨论tdd了的必要性了。
老马说的tdd是重构的保障,离开单元测试进行重构总是很不放心万一又引入了什么新bug。
重构这东西感觉就是写给coder的。
目标就是尽量让每一个类的体型都是大小正好,近似标准体型,比如:
每个函数有N行左右的代码,多了就拆,少了就合并;
每个类有N左右个方法,N个左右的属性,每个包有N个类,。。。。

这里的N一般取值很小,不大于10.
0 请登录后投票
   发表时间:2010-05-10   最后修改:2010-05-10
hatedance 写道
感觉上面的同学开始离题了,讨论tdd了的必要性了。
老马说的tdd是重构的保障,离开单元测试进行重构总是很不放心万一又引入了什么新bug。
重构这东西感觉就是写给coder的。
目标就是尽量让每一个类的体型都是大小正好,近似标准体型,比如:
每个函数有N行左右的代码,多了就拆,少了就合并;
每个类有N左右个方法,N个左右的属性,每个包有N个类,。。。。

这里的N一般取值很小,不大于10.

N -> 7 土 2
0 请登录后投票
   发表时间:2010-05-10  
lz说重构“过时”那么,哪些方面过时了呢?请赐教
0 请登录后投票
   发表时间:2010-05-11  
Joo 写道
sunway00 写道
C_J 写道

    作者推荐在编码阶段就开始构造单元测试,可为每个类写main方法来测试,这个我目前觉得还点苛刻了。

作者推荐的应该不是每个类写main方法,而是用Junit之类进行单元测试。在编码阶段构造单元测试说不上苛刻吧,要是按照敏捷的要求应该是TDD,写代码前先写测试呢。


即便是这样也是苛刻
第一,没有必要为每一个类作单元测试,否则何来的覆盖率之说
第二,为重点关注类写单元测试在现在大多数公司和企业也是不太现实,愿望很美好...



test coverage是重构的保证,保证不了正确性,重构就没有意义。
我的经验是DAO 100%,
BO的line coverage 100%
        branch coverage >50%
0 请登录后投票
   发表时间:2010-05-12  
guanliScott 写道
Joo 写道
sunway00 写道
C_J 写道

    作者推荐在编码阶段就开始构造单元测试,可为每个类写main方法来测试,这个我目前觉得还点苛刻了。

作者推荐的应该不是每个类写main方法,而是用Junit之类进行单元测试。在编码阶段构造单元测试说不上苛刻吧,要是按照敏捷的要求应该是TDD,写代码前先写测试呢。


即便是这样也是苛刻
第一,没有必要为每一个类作单元测试,否则何来的覆盖率之说
第二,为重点关注类写单元测试在现在大多数公司和企业也是不太现实,愿望很美好...



test coverage是重构的保证,保证不了正确性,重构就没有意义。
我的经验是DAO 100%,
BO的line coverage 100%
        branch coverage >50%

brach coverage >70%==基本
brach coverage >80%==良(大多数项目)
brach coverage >85%==优
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics