zoukankan      html  css  js  c++  java
  • Refresh 重构(Refactor)

    最近在闲暇之余重(第)温(一..次)此书, 首先能感受到的, 无论你是新程序员还是老程序员, 这本书都已经不具备太多的可读性了.

    由于本书成书年代久远, 那个时候软件行业还不够发达, 面向对象还没有被大数人理解, 加之编译器也非常落后, 设计模式也不深入人心, 所以文中提供的所谓重构的心法, 在当时或许有一些意义. 而今看来, 整书400多页的文字, 主要的思想就是「抽」, 无论是类, 接口, 方法, 逻辑, 还是参数. 但是为什么会有这么大的篇幅, 其中一半的内容是教你如何在一个IDE功能匮乏的年代, 以一个出错率更低的顺序, 来进行上面所说的多种抽象操作.

    当然我去除了大量书中已经没有任何价值的点后, 总结了如下的一些内容, 应该大多数大家已经在工作实践中已有体会, 主要还是总结一下, 温故知新吧.

    • 思想方面
      • 如果发现加特性很难, 就需要重构
      • 重构前需要想想有没有可靠的测试机制
      • 重构要微小步伐, 容易发现错误
      • Extract method是最简单的重构
      • 写出机器认识的代码容易, 写出人类容易理解的才是应该的, 最大的影响就是命名
      • 做移动重构时, 最好先复制粘贴, 测后再删除旧的代码
      • 对于另外对象的switch往往可以通过继承, 多态来取代
      • 三次遇到不合理的, 可能就是重构的时候了
      • 重构往往通过加隔离层进行
      • 不要过早发布接口
      • 性能优化应该基于良好的代码结构, 性能瓶颈往往只会在很小的代码片段里
      • 每次遇到一个bug, 尽量写个单元测试覆盖
      • 测试集中覆盖边缘case
    • 代码坏味道与手段
      • 重复代码
        • 抽方法
      • 大函数
        • 抽方法, 抽类
      • 大类
        • 抽类, 抽子类
      • 太多参数
        • 参数变方法, 抽参数对象
      • 加新功能修改多个函数
        • 抽子类
      • 加新功能需要改很多类
        • 挪方法, 挪成员
      • 函数过度依赖其他类
        • 挪方法, 抽方法
      • 同样的几个参数到处出现
        • 抽参数对象
      • 大量同样的基本类型做参数
        • 抽类, 不同表达式可抽进子类
      • 很多switch
        • 考虑用多态取代
      • 子类需平行同时添加
        • 先持有对方, 再挪方法, 再挪变量, 再合并
      • 没人用的类
        • 做内部类
      • 没太大用处的抽象, 参数, 命名
        • 删除, 重命名, 内联
      • 临时变量命名模糊
        • 抽方法, 抽类
      • 消息链过长, 对象转换过多
        • 对同一对象的使用抽方法, 推入消息链消除对象
      • 过度代理
        • 内联代理
      • 注释太多
        • 可能代码写的太难懂, 需要重构
    • 数据
      • 临时变量被赋值多次, 则可以抽成方法
      • 有时候需要提取多个临时变量对逻辑进行解释, 当然更好的可以再抽成方法
      • Java按值传递, 本质上是对象的引用按值传递
      • 移除中间人与隐藏委托是相辅相成的
      • 如果类无法更改, 就写个函数包装他, 类似于工厂方法?
      • 如果不能修改, Adapter模式常常用于扩展方法功能
      • 子类修改某些变量的获取可以通过自封装, 把变量抽象成函数
      • 成员如果不用改变, 就由引用变为值对象, 即immutable对象
      • 当业务复杂度变高需要将类之间单向关系改为双向绑定关系, 甚至一对多与多对一的关系
      • 双向绑定可能会造成很多僵尸对象, 增加复杂度与空间占用, 所以只有真正需要的时候用, 删除可以通过将内部绑定查询转移为传参, 再在调用的位置进行判断是否为僵尸对象
      • 不要使用Magic Number, 常量即可以优化储存, 又可读性高
      • 封装字段可以控制字段的读写, 称之为数据隐藏
      • 对于返回集合的函数需要返回只读副本, 如果需要修改, 则可另行提供修改方法
      • 原始类型替换成类, 有类型字段的类转换为多个子类, 或者抽象成策略模式, 从而合理改变数据结构
      • 如果子类只有常量, 可以抽成变量放父类, 再添加工厂方法创建, 降低复杂度
    • 条件表达式
      • 条件表达式很复杂的时候, 可以将条件, 执行代码进行封装, 更表意
      • 嵌套很深的条件表达式的每个结果都作为返回值的话, 可以简化为多个if+return, 类似于swift里面的guard, 或者kotlin里面的?:return, 书里叫卫语句(Guard Clauses)
      • 嵌套很深的条件表达式可以将范围大的if反向, 实现提前return
      • switch表达式有时候可以通过多态来取代
    • 函数调用
      • 函数最好读写分离
      • 抽象重复性的函数用以复用
      • switch构造可以替换成工厂方法
      • 从对象内拿出参数再传递给某函数不如直接将对象传入函数
      • 当函数的参数来自另外一个函数时, 也可以删掉参数, 把函数调用挪进去
      • 函数参数过多可以同对象替代
      • 如果不需要设置就不要提供set方法, 变量都需要为final
      • 有时候用抛异常替代返回错误码, 如果程序无法继续进行的话
      • 如果可以条件逻辑避免Runtime异常, 应不要无脑try/catch
    • 继承关系
      • 子类同样的方法应该向上提, 并将不同的地方抽象为抽象方法分别继承
      • 子类构造复制父类字段应该通过父类构造, super
      • 超类与子类差不多, 就合并
      • 逻辑相同, 类型不同可以通过模板函数, 模板类解决
      • 不能滥用继承, 组合代理好过继承, 但也有特殊, 如果需要使用委托函数所有函数或者大量, 则就需要继承, 不过这一点在kotlin里面也可以通过by来代理
    • 复杂的重构
      • 整理复杂的继承关系, 该抽接口抽接口, 摘出更多深层子类
      • 领域与表述分离, 就是UI与逻辑分离
      • 过程抽象为对象
      • 提炼继承体系
  • 相关阅读:
    【hihocoder1255 Mysterious Antiques in Sackler Museum】构造 枚举
    【hihocoder 1257 Snake Carpet】构造
    【HDU 5572 An Easy Physics Problem】计算几何基础
    【hihocoder 1258 Osu! Master】
    Coder-Strike 2014
    [不完全动态凸包]SGU277
    [成都七中]GCD
    [某模拟赛]鸡腿の乒乓
    [TCSRM518Div1]Nim
    BZOJ3289【莫队算法+树状数组+离散化】
  • 原文地址:https://www.cnblogs.com/mengdd/p/refresh-reactor.html
Copyright © 2011-2022 走看看