重构改善既有代码的设计(第三章))

重构的难题

数据库

  • 绝大多数的商用程序都与其背后的DataBase schema(数据库表格结构)紧密耦合在一起,DataBase schema如此难以修改的原因。
  • 数据迁移,常用手段是:系统分层–将DataBase schema和对象模型间的依赖降到最低,但是对数据库表的更改,这可能是一件漫长的工作。

在非对象数据库中,解决办法是:在对象模型和数据库模型之间插入一个分隔层,可以隔绝两个模型各自的变化。

修改接口

对于对象:允许分开修改软件模块的实现(implementation)和接口(interface)。

  • 对象: 可以安全的修改对象内部而不影响他人
  • 接口: 修改接口任何事情都有可能发生

如果某个接口的函数的所有调用者都能够控制,那么修改函数名称不会有任何问题。
当需要修改的接口是无法找到的,并且找到也不能修改的代码是,那么修改接口会成为问题。【已发布接口】
对于已发布的接口:

  1. 需要同时维护新旧两个接口,让旧接口继续工作
  2. 让旧接口调用新接口
  3. 当修改某个函数名称时,先留下旧函数,让它调用新函数
  4. 使用Java提供的旧接口标记:deprecated
  5. 尽量少的发布(public)的接口

代码的坏味道

重复的代码

  1. 同一个class内的两个函数含有相同表达式 ----Extract Method提炼出重复的代码,让这两个地点都调用被提炼出来的那段代码
  2. 两个子类含有相同的表达式----对两个class使用Extract Method,将其放到父类中
  3. 代码之间类似----运用Extract Method将相似部分和差异部分分开,用模版设计模式重构
  4. 两个独立的class内出现重复代码----对其中一个class使用Extract Class,将重复代码提炼到一个独立的class中,然后在另一个class内使用这个新的class。

过长函数

每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。99%的场合里,要把函数变小,只需要使用Extract Method。

  1. 函数内有大量的参数和变量和临时变量----需要把这些参数和临时变量当作参数,传递给新函数,导致可读性几乎没有任何提升
    • Introduce Parameter Object
    • Preserve Whole Object
    • Replace Method with Method Object
  2. 具体哪一行代码----寻找注释,条件式和循环常常也是提炼的信号
    • 条件式----分解条件式
    • 循环----将循环和其内的代码提炼到一个独立函数中

过大类

想利用单一class做太多事,往往会出现其太多的Instance变量,重复代码也就接踵而至

  1. 运用Extract Class将Class内彼此相关的变量,将它们放在一起提炼到新class中。
  2. class并非在所有时刻都使用所有子类中的变量,可以多次使用Extract Class或Extract Subclass。
  3. 先确定客服端如何使用它们,然后Extract Interface为每一种使用方式提炼出一个接口,了解如何分解这个class。

过长参数列

全局数据是邪恶的东西,太长的参数列难以理解,太多参数会造成前后不一致、不易使用,而且一旦你需要更多数据,就不得不修改它。

发散式改变

希望软件能够更容易被修改,一旦需要需改,希望能够跳到系统的某一点,只在该处修改。如果某个class经常因为不同的原因在不同的方向上发生改变,就需要警惕了。

散弹式修改

如果遇到某种情况,需要在不同的class内作出许多小的修改以响应之,需要修改的代码散布到四处,很难找到它们,也很容易忘记某个重要的修改。

依恋情结

无数次经验里,我们看到某个函数为了计算某值,从另一个对象中调用了几乎一半的取值函数。
方法:将这个函数移到另一个类中。判断那个class拥有最多【此函数使用】的数据,然后把这个函数和那些数据放在一起。

数据泥团

数据喜欢成群结队在一起。总是绑定在一起出现的数据应该放进属于它们自己的对象中。

  1. 找出这些数据的值域形式出现点,Extract Class将它们提炼到一个独立对象中。
  2. 对于函数签名,运用Introduce Parameter Object或者Preserve Whole Object为其减肥

基本类型偏执

放在一起的值域:运用Extract Class。
参数列表中基本类型数据:Introduce Parameter Object
array中挑选数据:Replace Array with Object

switch惊悚现身

面向对象程序设计最明显的特征:少用switch(或case)语句
**面向对象中的多态概念可以为此提供优雅的解决办法

  1. 使用Extract Method将switch语句提炼到一个独立的函数中
  2. Move Method将它搬到需要多态性的class中

狎昵关系

有时你会看到两个classes过于亲密, 花费太多时间去探究彼此的private成分。
你可以采用 Move Method 和 Move Field 帮它们划清界线, 从而减少狎昵行径。
继承往往造成过度亲密,因为subclass对superclass的了解总是超过superclass的主观愿望。

过多的注释

常常会有这样的情况: 你看到一段代码有着长长的注释, 然后发现, 这些注释之所以存在乃是因为代码很糟糕。 这种情况的发生次数之多, 实 在令人吃惊
TIP: 当你感觉需要撰写注释, 请先尝试重构, 试着让所有注释都变得多余。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值