跳转至

代码的坏味道

  1. 神秘命名(Mysterious Name)

    • 整洁的代码最终要的就是好的名字,所以我们会深思熟虑如何给函数、模块、变量和类命名,使它们能清晰的表明自己的功能和功法。
  2. 重复代码(Duplicated Code)

    • 一旦重复代码的存在,阅读重复代码你就要加倍仔细,留意其差异。导致很容易出错。
  3. 过长函数(Long Function)

    • 函数越长越难理解。

    • 如何提炼:

      • 寻找注释;
      • 条件表达式;
      • 循环;
  4. 过长参数列表(Long Parameter List)

    • 过长的参数列表也会使人产生迷惑

    • 如何解决

      • 第一个参数可以获取第二个参数:去掉第二个参数;
      • 正在从现有数据结构中抽出很多数据:保持原有对象;
      • 有几个参数总是同时出现:合并这几个参数为一个对象;
      • 多个函数拥有同样的参数:引入一个类;
  5. 全局数据(Global Data)

    • 问题在于全局都可以修改,导致不知道谁修改了他

    • 如何解决:

      • 封装变量,进行控制和记录
  6. 可变数据(Mutable Data)

    • 一个功能使用的变量,在另一处被改变了

    • 如何解决:

      • 封装变量
      • 拆分变量
      • 移动语句、提炼函数
      • 查询和修改分离
      • 已查询取代派生变量
      • 函数组合成类、函数组合成变换
      • 引用对象改为值对象
  7. 发散式变化(Divergent Change)

    • 需要修改时,只需跳到系统的某一点,只在该处做修改,如果做不到这一点,那就很糟糕
    • 如何解决:
      • 拆分阶段
      • 搬移函数
      • 提炼函数
      • 提炼类
  8. 散弹式修改(Shotgun Surgery)

    • 如果每遇到某种变换,你都必须在许多不同的类内做出小的修改,你所面临的就是散弹式修改。很难找到修改的位置,也容易错过某个重要的修改。
    • 如何解决:
      • 搬移函数、搬移字段
      • 组合函数成类
      • 组合函数成变换
      • 内联函数、内联类
  9. 依恋情节(Feature Envy)

    • 一个函数跟另一个模块中的函数或者数据交流格外频繁,甚至远甚于本模块内部的交流,这就是依恋情结的典型案例。
    • 如何解决
      • 搬移函数
      • 提炼函数、搬移函数
  10. 数据泥团(Data Clumps)

    • 你常常可以在很多地方看到相同的三四项数据:两个类中的字段、函数等。

    • 如何解决

      • 提炼类、引入参数对象、保持对象完整;
  11. 基本类型偏执(Primitive Obsession)

    • 大多数编程都适用基本类型,一些库会引入小对象,如日期。很对程序员不愿意创建自己的问题域有用的基本类型,如:钱、坐标、范围等。于是把钱作为一个普通的数字进行计算无视了其钱的其他属性

    • 如何解决

      • 以对象取代基本类型
      • 以子类取代类型码
      • 加上多态取代表达式
  12. 重复的switch(Repeated Switches)

    • 任何switch语句都应该以多态取代条件表达式
  13. 循环语句(Loops)

    • 鄙视循环语句

    • 如何解决

      • 管道取代循环
  14. 冗赘的元素(Lazy Element)

    • 起初在编写的时候,程序员希望代码十分完善,功能强大但随着重构的进行只剩下一个函数了

    • 如何解决

      • 使用内联函数、内联类
      • 折叠继承体系
  15. 夸夸其谈通用性(Speculative Generality)

    • 如果用不到,那就不值得

    • 如何解决:

      • 内联函数、内联类

      • 改变函数声明

  16. 临时字段(Temporary Field)

    • 其内某个字段仅为某种特定情况而设。这样的代码不易理解,在代码未被使用的时候猜想他当初的目的,会使人发疯。

    • 如何解决

      • 提炼类、搬移函数
  17. 过长的消息链(Message Chains)

    • 到你看到一个对象请求另一个对象,然后再请求另一个对象 ······ 这就是消息链。这就意味着强耦合。

    • 如何解决:

      • 隐藏委托关系,先观察消息链最终得到了什么看看是否可以提炼函数,在运用搬移函数把这个函数推入消息链。
  18. 中间人(Middle Man)

    • 对象的基本特征就是封装,封装意味着委托。但是过度运用委托。你会看到某各类的接口有一半的函数都是委托给其他类。那这就是过度委托。

    • 如何解决:

      • 移除中间人、运用内联函数
  19. 内幕交易(Insider Trading)

    • 模块之间大量交换数据,这会增加模块间的耦合。

    • 如何解决:

      • 搬移函数、搬移字段减少交流,建立新类管理;或者使用隐藏委托关系。
  20. 过大的类(Large Class)

    • 一个类想做的事情太多了,往往就会出现好多字段。这样重复的代码就会接踵而至。

    • 如何解决:

      • 提炼超类、提炼子类
  21. 异曲同工的类(Alternative Classes with Different Interfaces)

    • 使用类的好处是可以替换:今天使用这个类,未来可以换成另一个类。但只有两个类的接口一致时,才能做这种替换。

    • 如何解决:

      • 改变函数声明,反复使用搬移函数将某些行为移入类中,指导两者协议一致,重复代码使用提炼超类补偿一下;
  22. 纯数据类(Data Class)

    • 它们拥有一些字段,以及用于访问读写这些字段的函数,除此一无是处。

    • 如何解决:

      • 封装记录、移除设值函数;
      • 找出取值设值的位置,搬移函数、提炼函数
  23. 被拒绝的遗赠(Refused Bequest)

    • 子类应该继承超类的函数和数据。戴氏他们不想或者不需要继承。

    • 如何解决:

      • 需要为这个子类新建一个兄弟类,在运用函数下移和字段下移把用不到的推给兄弟类
  24. 注释(Comments)

    • 当你感觉撰写注释时,请先尝试重构,试着让所有的注释都变得多余;