代码的坏味道——《重构——改善既有代码的设计》

1. Duplicated Code

重复代码,在程序中多次出现的相同结构或功能的代码

  • 同一个类中的两个函数含有相同的表达式
  • 两个互为兄弟的子类中含相同的表达式
  • 相互独立的类中出现相同表达式

2. Long Method

  • 过长的函数难以理解及维护
  • 段函数或间接层具有很强的解释能力、共享能力和选择能力
  • 面向对象几乎完全免除了进程内函数调用的开销
  • 短函数功能单一明确,可以起一个比较贴近功能的名称
  • 避免过长的参数列表
  • 查找注释过的代码,通过可以提取出来形成小函数
  • 条件表达式和循环代码也可以提取

3. Large Class

  • 一个类若需要做过多的事情,就会出现大量实例对象,进而导致产生重复代码
  • 将类中彼此相关的变量提取到新类或子类中(可通过变量前缀或字尾区分是否相关)
  • 根据类接口的调用方式来确定该类对外的接口分解

4. Long Parameter List

  • 过长的参数列表难以理解,可能造成前后不一致,不易修改
  • 可以通过宿主对象,或将参数封装成对象传入都可有效减少入参
  • 避免较大对象的传入,此时需要权衡是否以参数列表传入

5. Divergent Change

  • 当类因为不同的场景需求导致其功能向不同的方向发生变化时,那么当你要修改它时,就无法集中于一点进行修改
  • 最好是每一种变化对应一个类的修改

6. Shotgun Surgery

  • 一种需求的变化可能会是你修改多个小类,这样可能会导致遗忘某处修改
  • 建议尽量将应对这一变化修改的变量和代码能集中到同一个类中
  • 与Divergent Change提倡的似乎有点相反,但两者间尽量寻求平衡点,视具体场景而定

7. Feature Envy

  • 当一个类中函数大量调用其他类对象中的接口和数据时,可以考虑将其分解后,移至被调用的类中
  • 这样可能会导致发散变化,Stategy和Visitor模式可以将一起变化的东西集中在一处

8. Data Clumps

  • 有些数据或字段经常会重复出现:两个类中拥有相同字段,多个函数签名中有相同的参数, 这种问题可将数据集中到同一个对象中,然后直接操作对象
  • 可以通过删除参数中的一项,看是否影响其他数据,若有,则需要提取

9. Primitive Obsession

  • 程序中常用基本数据类型和结构类型
  • 可使用对象替换一些基本数据类型,构成自定义的小型对象类型数据使用

10. Switch statements

  • 面向对象编程中建议尽量少使用switch,而使用多台替代
  • 根据类型码提取相关的函数或类,再在提取类中考虑使用多态
  • 若进单一函数中使用选择事例,那没必要改成多态

11. Parallel Inheritance Hierarchies

  • 当你增加一个类的子类时,需要同时增加另一个平行类的子类
  • 通常观察某个继承体系的类名称前缀和另一个集成体系的类名称前缀相同,基本属于此类味道
  • 可以让一个继承体系的实例引用另一个继承体系的实例

12. Lazy Class

  • 每个类的存在都必须确实履行它的责任
  • 若发现设计了应对未知变化的类,却目前仍没使用,或其他原因导致某个类不再使用,可以删除掉

13. Speculative Generality

  • 针对未来可能遇到的变化而设计的类,目前未被使用的情况,可以先删除
  • 抽象类作用不大,不必要的委托,未被使用的参数,函数名带有多余的意味等都需要修改
  • 若函数或类的唯一用户是测试用例,那么没必要保留

14. Temporary Field

  • 类中有时会存在一些应对某种特定情况的变量,这种变量的设置目的很难在其使用之前猜测到用途
  • 可以将这种变量及相关代码提取到单一的类中管理

15. Message Chains

  • 对象间的顺次调用就是消息链,客户代码与查找过程中的导航结构紧密耦合,一旦对象间的关系发生变化,那么客户代码也要随之变化
  • 先观察消息链最终得到的对象,然后将与其相关的代码提取到一个函数中,再将这个函数推入消息链

16. Middle Man

  • 某些类接口有一半的函数都委托给其他类,属于过度运用
  • 尽量让类直接与真正负责的对象打交道
  • 这种函数较少时可使用内联方法将他们放入调用端
  • 若委托对象还有其他行为,可以用继承代替代理

17. Inappropriate Intimacy

  • 两个类中的默写字段或函数功能含混不清或十分接近,需要划清界限
  • 可以将双向关联改成单向关联
  • 可以提取公共类
  • 可以使用代理

18. Alternative Classes with Different Interfaces

  • 若两个类中的接口功能一致,命名不同,首先需要重命名,保持一致,其次需要将功能一致的代码只维护一份

19. Incomplete Library Class

  • 针对设计不完美的三方类库,难以修改
  • Introduce Foreign Method 用于修改类库的一两个函数
  • Introduce Local Extension 用于添加额外行为

20. Data Class

  • 纯数据类型需要对私有字段进行封装,对只读字段不要添加set方法

21. Refused Bequest

22. Comments

  • 过多的注释需要重构

猜你喜欢

转载自blog.csdn.net/tianzhiyi1989sq/article/details/104209291