重构(Refactoring)技巧读书笔记 之三
General Refactoring Tips, Part 3
动了情的至尊宝在那个月圆之夜有感而发:长夜漫漫,无心睡眠。从此,他的夜生活变得多姿多彩起来。唉,我以为只有至尊宝才有这等幸运。
想起放在抽屉的《重构》,遂拜读大师的作品来催眠,度过一个无心睡眠的漫漫长夜。
……
本文继续重构(Refactoring)技巧读书笔记系列。重构虽然是对现有的代码进行设计,以提高代码的质量和灵活性,但实际上,如果软件工程师掌握重构技术,对其初期的软件设计也有很好的指导,减少不当设计或设计不足,减少代码坏味道(Bad Smell in Codes),构建良好的系统。
注:本文重构策略的名称及其大部分内容来自《重构-改善既有代码的设计》一书,Martin Fowler 著,侯捷等译。
一、代码坏味道(Bad Smell in Codes)及其重构策略
11.Parallel Inheritance Hierarchies(平行继承体系)
现象:为某个class增加一个subclass时,也必须为另一个class相应增加一个subclass。重构策略: 在一个class继承体系的对象中引用(refer to)另一个class继承体系的对象,然后运用Move Method和Move Field将被引用class中的一些方法和成员变量迁移宿主class中,消除被引用class的继承体系(注:这种平行继承体系好象比较少见也)。
12.Lazy Class(冗赘类)
现象:某一些class由于种种原因,现在已经不再承担足够责任,有些多余了。如同国有企业冗余人员一样,需要下岗了。
重构策略:通过Collapse Hierarchy,将这些冗余的class合并到superclass或subclass中,或者通过Inline Class(与Extract Class相反),将这些冗余class中的所有Method/Field迁移到其他相关的class中。
13.Speculative Generality(夸夸其谈未来性)
现象:系统中出现一些无用的abstract class,或者非必要的delegation(委托),或者多余的参数等等。
重构策略:分别使用Collapse Hierarchy合并abstract class,使用Inline Class移除非必要的delegation,使用Remove Parameter删除多余的参数。
14.Temporary Field(令人迷惑的暂时值域)
现象:class中存在一些Field,这些Field只在某种非常特定的情况下需要。
重构策略:通过Extract Class将这些孤独的Field及其相关的Method移植的一些新的Class中。提炼出来的新Class可能没有任何抽象意义,只是提供Method的调用,这些新Class一般称为Method Object。
15.Message Chains(过度耦合的消息链)
现象:向一个对象请求另一个对象,然后再向后者请求另一个对象,……,这就是Message Chain,意味着Message Chain中任何改变,将导致Client端不得不修改。
重构策略:通过Hide Delegate(隐藏委托关系)消除Message Chain,具体做法是在Message Chain的任何地方通过Extract Method建立一个简单委托(Delegation)函数,来减少耦合(Coupling)。
16.Middle Man(中间转手人)
现象:过度运用delegation,某个/某些Class接口有一半的函数都委托给其他class,这样就是过度delegation。
重构策略:运用Remove Middle Man,移除简单的委托动作(也就是移除委托函数),让client直接调用delegate受托对象。和上面的Hide Delegate(隐藏委托关系)刚好相反的过程。
由于系统在不断的变化和调整,因此[合适的隐藏程度]这个尺度也在相应的变化,Hide Delegate和Remove Middle Man重构策略可以系统适应这种变化。
另外,可保留一部分委托关系(delegation),同时也让Client也直接使用delegate受托对象。
17.Inappropriate Intimacy(狎昵关系)
现象:两个Class过分亲密,彼此总是希望了解对方的private成分。
重构策略:可以采用Move Method和Move Field来帮助他们划清界限,减少他们之间亲密行为。或者运用Change Bidirectional Association to Unidirectional,将双向关联改为单向,降低Class之间过多的依存性(inter-dependencies)。或者通过Extract Class将两个Class之间的共同点移植到一个新的Class中。
18.Alternative Classes with Different Interfaces(异曲同工的类)
现象:两个函数做相同的事情,却有不同的signature。
重构策略:使用Rename Method,根据他们的用途来重命名。另外,可以适当运用Move Method迁移某些行为,使Classes的接口保持一致。
19.Incomplete Library Class(不完美的程序库类)
现象:Library Class(类库)设计不是很完美,我们需要添加额外的方法。
重构策略:如果可以修改Library Class的Source Code,直接修改最好。如果无法直接修改Library Class,并且只想修改Library Class内的一两个函数,可以采用Introduce Foreign Method策略:在Client Class中建立一个函数,以外加函数的方式来实现一项新功能(一般而言,以server class实例作为该函数的第一个参数)。
如果需要建立大量的额外函数,可应该采用Introduce Local Extension:建立一个新class,使它包含额外函数,并且这个class或者继承或者wrap(包装)source class。
20.Data Class(纯稚的数据类)
现象:Data Class指:一些Class拥有Fields,以及用来访问Fields的getter/setter函数,但是没有其他的功能函数。(感觉这些Data Class如同Entity Class或Parameter Class,用来传递参数,我认为这种情况下没有必要重构。)
重构策略:找出其他class中访问Data Class中的getter/setter的函数,尝试以Move Method将这些函数移植到Data Class中,实现将数据和操作行为(方法)包装在一起,也让Data Class承担一定的责任(方法)。
21.Refused Bequest(被拒绝的遗赠)
现象:Subclass不想或不需要继承superclass的部分函数和Field。
重构策略:为subclass新建一个兄弟(sibling class),再运用Push Down Method和Push Down Field将superclass中的相应函数和Field下推到兄弟class,这样superclass就只包含subclass共享的东西了。其实,也就是将superclass中一些与特定的函数和Field放到特定的subclass中,superclass中仅包含subclass共享的函数和Field。
如果不想修改superclass,还可以运用Replace Inheritance with Delegation来达到目的。也就是以委托取代继承,在subclass中新建一个Field来保存superclass对象,去除subclass对superclass的继承关系,委托或调用superclass的方法来完成目的。
22.Comments(过多的注释)
现象:(晕倒,这个也要重构,Remove掉所有的Comments吗?不是。)当代码中出现一段长长的注释,一般是由于代码比较糟糕,需要进行重构,除去代码的坏味道。
重构策略:通过上面提及的各种重构策略,将代码的坏味道去除,使注释变成多余。
如果需要注释/解释一段代码做了什么,则可以试试Extract Method,提取出一个独立的函数,让函数名称解释该函数的用途/功能。另外,如果觉得需要注释来说明系统的某些假设条件,
也可尝试使用Introduce Assertion(引入断言),来明确标明这些假设。
当你感觉需要撰写注释时,请先尝试重构,试着让所有的注释都变得多余。
代码的坏味道(Bad Smell in Codes)学习完