当前位置

网站首页> 程序设计 > 开源项目 > 程序开发 > 浏览文章

《Refactoring》:重构 - beanlam

作者:小梦 来源: 网络 时间: 2024-02-23 阅读:

概念

什么是重构(refactoring);

在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。

重构的每个步骤都很简单,甚至显得过于简单:

  • 把某个字段从一个类移到另一个类

  • 把某些代码从一个函数来出来构成另一个函数

  • 在继承体系中把某些代码推上推下

  • ......等等

重构的目的:使软件更容易被理解和修改

重构的原则

我不是一个伟大的程序员,但只是一个有着一些优秀习惯的程序员。 By Kent Beck

为何重构

  • 重构改进软件设计

  • 重构使软件更容易理解

  • 重构帮助找到bug

  • 重构提高编程速度

何时重构

  • 三次法则

事不过三,三则重构

  • 添加功能时重构

  • 修改错误时重构

  • 复审代码时重构

代码的坏味道

Duplicated Code(重复代码)

  • 同一个类的两个函数拥有相同的表达式

  • 两个互为兄弟的子类内含相同的表达式

  • 两个毫不相关的类出现duplicated code.

Long Method(过长函数)

分成小函数,消除临时变量,
遇到注释、条件表达式或者循环时,考虑提炼成小函数。

Large Class(过大的类)

想利用单个类做太多事情,往往会出现太多实例变量,从而导致duplicated code;
如果类内的数个变量有相同的前缀或滋味,考虑把它们提炼到一个子类中。
同样对于方法也一样。

Long Parameter List(过长参数列表)

考虑将对象作为参数传递给方法

Divergent Change(发散式变化)

我们希望软件能够更容易被修改--毕竟软件再怎么说本来就该是“软”的

如果某个类经常因为不同的原因在不同的方向上发生变化。
当你看着一个类说:"呃,如果新加入一个数据库,我必须修改这三个函数;如果新出现一种金融工具,我必须修改这四个函数"。
那么此时也许将这个对象分成两个会更好,这么一来每个对象就可以只因一种变化而需要修改。

Shotgun Surgery(霰弹式修改)

Divergent Change是指"一个类受多种变化的影响", Shotgun Surgery则是指"一种变化引发多个类相应修改"。
可以把所有需要修改的代码放进同一个类,通常可以运用Inline Class把一系列相关行为放进同一个类。

Feature Envy(依恋情结)

某个函数为了计算某个值,从另一个对象那儿调用了几乎半打的取值函数。
那么要考虑把这个函数移动至另一个地点,例如这另一个对象。

Data Clumps(数据泥团)

两个类中相同的字段、许多函数签名中相同的参数。
这些总是绑在一起的数据真应该拥有属于它们自己的对象。

Primitive Obsession(基本类型偏执)

如果有一组应该总是被放在一起的字段,可以提炼到一个对象中。
例如结合数值和币种的money,由一个起始值和一个结束值组成的range类。

Switch Statements(switch惊悚现身)

面向对象程序的一个最明显特征就是:少用switch或case语句。

一般来说,一看到switch语句,就应该考虑以多态来替换它。

Parallel Inheritance Hierarchies(平行继承体系)

平行继承体系其实是Shotgun Surgery的特殊情况。
这种情况下,每当你为某个类增加一个子类,必须也为另一个类相应增加一个子类。
策略:让一个继承体系的实例引用另一个继承体系的实例。

Lazy Class(冗赘类)

如果一个类的存在没有多大作用,考虑删除,或者Inline。

Speculative Generality(夸夸其谈未来性)

不要随便定义太多钩子来处理一些非必要的不会发生的事情。

Temporary Field(令人迷惑的暂时字段)

实例变量应该是对象实实在在需要的变量,是一种属性,而不是在某些特定情况下才会用到的临时变量。

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

一个对象请求另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象。
这就是消息链。耦合程度过高。

Middle Man(中间人)

类的委托动作太多,导致这个类不干实事。还不如直接越过这个middle man,与真正干实事的类打交道。

Inappropriate Intimacy(狎昵关系)

两个类过于亲密,花费太多时间去探究彼此的private成分。

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

如果两个函数做同一件事,却有着不同的签名,需要重新命名。

Incomplete Library Class(不完美的库类)

类库经常不完美。
想要修改库类的一两个函数,可以运用 Introduce Foreign Method。
如果想要添加一大堆额外行为,就得运用Introduce Local Extension.

Data Class(纯稚的数据类)

Data Class是指POJO。
不应该拥有public字段
对容器类字段进行良好包装
不应该被修改的字段,删除赋值函数

Refused Bequest(被拒绝的遗赠)

子类有时候会拒绝继承超类的一些实现。

Comments(过多的注释)

很多时候,comment的存在,是因为代码很糟糕。
应该多考虑怎么优化代码。
注释通常用来标记TODO,以及为什么这么做。

构筑测试体系

JUnit测试

了解JUnit测试框架的使用

热点阅读

网友最爱