重构:代码的味道与消除方法

来源:互联网 发布:mac lamp 编辑:程序博客网 时间:2024/04/28 19:28
在敏捷开发模式下,随着业务的发展,需求的变化,新功能的增加,人员的变更,软件需要不断的修改原有的功能、追加新的功能、修改发现的缺陷等等。

对于部分很老的业务,软件也许已经经过几个、几十个、甚至上百个人的修改,面目全非。

于是,bug越来越多,越来越难维护,新的需求越来越难实现,软件的构架对新的需求渐渐的失去支持能力。这就是这个软件系统的生命走到尽头的时候。

    代码的味道是高水平程序员对好程序的一种感觉,他们具备一种能力,即使不涉及程序代码的具体实现就能看出你的设计是否合理。
     如果代码有异味,那么你需要进行Refactorying.

1. Duplicated Code(重复的代码)

  • 症状:

–  重复的表达式

–  不同算法做相同的事

–  类似代码

  • 措施:

–  一个类中包含两段重复代码时,使用提炼方法置于一处

–  两个相同层次的类含有重复代码时,提炼方法,方法上移

–  两个无关类中出现重复代码时,提炼方法至其中一个类或其他类中供调用

臭味行列中首当其冲的就是Duplicated Code。如果你在一个以上的地点看到相同的程序结构,那么当可肯定:设法将它们合而为一,程序会变得更好。

2. Long Method(长函数)

  • 症状:

–  存在大量的代码行

–  注释

–  条件和循环

  • 措施:

–  每当需要注释时,写一个方法来代替注释

–  绝大多数场合下,采取提炼方法技术来缩短函数

–  方法带有很多参数和临时变量时,采取查询替换临时变量链式调用替换临时变量来消除临时变量;采用引入参数对象保留完整对象技术瘦身参数列表;重型武器:使用方法对象替换方法

–  使用分解条件语句处理条件表达式;使用集合闭包方法替换循环

拥有[短函数](short methods)的对象会活得比较好、比较长。

3. Large Class(过大类)

  • 症状:

–  出现太多实例变量

–  包含太多代码

  • 措施:

–  提炼类把一些变量打包

–  可以作为子类时,提炼子类

–  无法作为委托时,提炼模块

4. Long Parameter List(过长参数列)

  • 症状:

–  参数列表过长

–  参数列表变化频繁

  • 措施:

–  传递对象,使方法自己获取它需要的参数

–  参数来自同一对象或是对象本身,保留整个对象为参数

–  参数来自不同对象,引入参数对象或者引入命名参数

刚开始学习编程的时候,老师教我们:把函数所需的所有东西都以参数传递进去。

5. Divergent Change(发散式变化)

  • 症状:

–  一个类因为不同的理由以不同的方式修改

  • 措施:

–  将两类变化涉及的方法拆为两个对象,每个对象只因为同一类变化而变化

–  将某种特定原因造成的所有变化提炼为一个新类,新类处理这一类变化

6. Shotgun Surgery(霰弹式修改)

  • 症状:

–  发生一次改变时,需要修改多个类的多个地方

  • 措施:

–  使用移动字段和移动方法将所有修改集中到单个类中。若现有类无好的候选者,创建;通常可以使用内联化类将整组行为整合到一起。

7. Feature Envy(依恋情结)

  • 症状:

–  一个方法调用其他类的方法比较多

–  一个方法调用到多个类的功能

  • 措施:

–  移动方法至另一适当的对象中

–  看哪个类含有最多的数据就把方法和那些数据放在一起

8. Data Clumps(数据泥团)

  • 症状:

–  两个类中相同的实例变量

–  许多方法签名中相同的参数

  • 措施:

–  对于实例变量,使用提炼类将其变成一个对象

–  对于方法签名,引入参数对象保留完整对象来瘦身

9. Primitive Obsession(基本型别偏执)

  • 症状:

–  使用了基本类型(fixnumstringarray

  • 措施:

–  使用对象替换数据值

–  使用多态替换类型码

–  使用模块扩展替换类型码

–  使用状态或策略模式替换类型码

–  使用对象替换数组

10. Switch Statements(switch惊悚现身)

  • 症状:

–  代码使用了case语句

  • 措施:

–  用多态替换case语句

  • 提炼方法,先把case语句提炼出来;
  • 移动方法至需要多态行为的类;
  • 选择技术:使用多态替换类型码、模块扩展替换类型码、状态或策略模式替换类型码

–  若分支很少,只在一个方法里起作用,使用显示方法替换参数引入Null对象来替换case语句

面向对象程序的一个最明显特征就是:少用switch(case)语句。从本质上说,switch语句的问题在于重复。你常会发现同样的switch语句散布于不同的地点。如果要为它添加一个新的case子句,你必须找到所有switch语句并修改它们。面向的多态概念可为此带来优雅的解决办法。

11. Parallel Inheritance Hierarchies(平等继承体系)

  • 症状:

–  为某个类增加子类时,必须为另一个类增加子类

–  某个继承体系类名前缀和另一个继承体系类名前缀相同

  • 措施:

–  使用移动字段和移动方法

12. Lazy Class(冗赘类)

  • 症状

–  类并没有做什么工作

  • 措施:

–  削减层次

–  内联化类或内联化模块

13. Speculative Generality(夸夸其谈未来性)

  • 症状:

–  类或模块没太大用处

–  方法、代码分支,或整个类的用户只有测试用例

  • 措施:

–  类或模块没太大用处,使用削减层次

–  不必要的委托,通过内联化类来移除

–  带有未使用参数的方法,使用移除参数

14. Temporary Field(令人迷惑的暂时值域)

  • 症状:

–  某个实例变量仅为某种情况而设置

–  某些实例变量仅为某个函数的复杂算法少传参数而设置

  • 措施:

–  提炼类,封装这些变量和需要他们的方法为方法对象

–  引入null对象为变量无效时创建额外组件,消除条件代码

15. Message Chains(过度耦合的消息链)

  • 症状:

–  一长串的 get_This 或临时变量

  • 措施:

–  使用隐藏委托技术

16. Middle Man(中间人)

  • 症状:

–  一个类的接口中有很多方法在委托另一个类

  • 措施:

–  这种方法数目很多时,使用移除中间人技术,直接和干活的对象打交道

–  这种方法的数目不多时,内联化方法到调用者中

–  这种方法包含额外的行为时,使用层次替换委托,将实际对象变成一个模块

17. Inappropriate Intimacy(过分亲密)

  • 症状

–  一个类访问了另一个类的私有部分。

  • 措施

–  使用移动方法和移动字段可以降低亲密程度

–  将双向关联改成单向

–  使用提炼类将公共部分提炼到安全之处

–  子类知道太多父类不想让他们知道的东西,使用委托替换继承让他们离家

18. Alternative Classes with Different Interfaces(异曲同工的类)

  • 症状:

–  完成相同工作,但却使用了不同的方法名

  • 措施:

–  使用重命名方法

–  使用移动方法将行为移到类中

–  因此出现冗余代码时,使用提炼模块引入继承来修正

19. Incomplete Library Class(不完美的程序库类)

  • 症状:

–  类库中函数构造的不够好,想扩展时可能很棘手

  • 措施:

–  使用移动方法将需要的行为直接移到类库中去

20. Data Class(幼稚的数据类)

  • 症状:

–  类仅由属性构成,纯粹用来持有数据,过分细致的依赖于其他类

  • 措施:

–  对任何不应被修改的实例变量采用移除设值方法

–  运用封装集合技术封装集合实例变量

–  尝试移动方法将相关行为移到数据类中,对一些设值方法和取值方法使用隐藏方法

21. Refused Bequest(被拒绝的遗赠)

  • 症状

–  子类不需要或仅需少部分父类的方法和数据

  • 措施

–  创建兄弟子类,使用方法下移,将所有不用的方法移到兄弟类中(不推荐)

–  若子类冲用了行为却不想支持父类里的公共方法时,应该使用委托替换继承技术

22. Comments(过多的注释)

  • 症状:

–  存在注释

  • 措施:

–  提炼方法替代注释

–  提炼之后还需注释,则重命名方法

–  若需注明系统所需状态规则,则引入断言

    在系统开发中我就发现,很多人写的代码有大片大片的注释,乱七八糟的格式,看起来就像稻草堆一样。注释掉的代码就要删除,即使将来需要还原还可以从版本控制工具中找到。提交的代码一定要干净。 

  1. 狂热的元编程
  • 症状:

–  元编程技术产生难懂的代码

  • 措施:

–  使用动态方法定义替换动态接收器去除元编程

–  不去除时,使用隔离动态接收器来分隔疑虑

24. 脱节的API

  • 症状:

–  为了灵活性而建立的细致、脱节的API,外加很多配置选项

  • 措施:

–  同样的配置选项不断被重复使用时,引入网关用简化的方式和API交互

–  引入表达式构造器可同时作用于内部和外部API

25. 不断重复的样板文件

  • 症状:

–  重复的样板文件

  • 措施:

–  提炼方法

–  太普遍的方法,引入类标注

0 0
原创粉丝点击