Contents
  1. 1. 何为重构
  2. 2. 重构的原动力
  3. 3. 何时重构
  4. 4. 重构方法
    1. 4.1. 简化条件表达式
    2. 4.2. Organizing Data
    3. 4.3. Moving Features Between Objects
    4. 4.4. 简化函数调用
    5. 4.5. 处理继承关系
  • 感想
  • 最近在写代码的时候,发现之前写的代码各种ifelse嵌套,类函数过多,函数体过长,函数变量命名不清晰,遂决定重构之,于此同时看了重构这本书,收益颇多!

    整本书从data,method,class,module,system的这几个层面去讲如何重构,重构的基本原则以及注意事项依次来编写高质量,可维护,可扩展的代码,主要读书笔记如下:

    何为重构

    在不改变软件可观察行为的前提之下,使用一系列重构方法,对软件内部结构进行调整,提高代码的可理解性,降低扩展成本

    重构的原动力

    当代码的设计无法帮助我们轻松添加新的特性(无法扩展),因此需要重构程序使程序满足以下条件:

    • 容易阅读
    • 所有逻辑都只在唯一地点指定
    • 新的改动不会危及现有行为
    • 尽可能简单表达条件逻辑

    在重构的过程中我们会发现Middle Tier(中间层)会被经常使用,使用中间层的好处主要体现在以下几个方面:

    • 允许逻辑共享,单个函数在多个地方进行调用
    • 分开解释意图和实现(类和函数的名字可以表达自己的意图)
    • 隔离变化
    • 封装条件逻辑

    何时重构

    如果每次对代码的更改都会做重复的事情,那么就必须重构

    修改接口

    对于对象而言可以分开修改软件模块的实现和接口,对于模块的实现可以任意进行修改而不影响他人,但是不能随意更改接口

    重构方法

    简化条件表达式

    当函数中如果出现多层if,else嵌套,一长串的switch语句,程序的可读性是非常差的,我们可以用以下几点重构之:

    • 从if,then,else中分解条件表达式(提炼独立的函数),突出条件逻辑,更清楚的表明每个分支的作用(增加可读性,见其名知其意
    • 合并条件表达式(如果一系列条件测试得到相同的结果,那么将所有提交测试提炼成一个独立的函数)(减少条件表达式
    • 合并重复的条件片段条件表达式中每个分支都有相同的代码,在相同代码不随条件表达式的改变而改变的前提下,将相同代码移至条件表达式外(减少冗余代码
    • 以卫语句取代嵌套条件表达式使用卫语句表现所有的特殊情况,卫语句要么从函数中返回,要么抛出一个异常(针对单一出口的观点,最好在不影响代码可读性的情况下才使用)
    • 以多态取代条件表达式:因为多态的出现,导致基于类型的switch语句和基于类型名称的if-else语句很少出现,对于多个if-else或者switch只用一个对基类的判断即可,那么在运行时中自动会调用相应类的方法(不必询问对象是什么,只管调用对应的的行为)(减少switch 的case语句
    • 引入null对象P260
      • 实现一个空对象,覆盖基类的isNull方法()返回true,
      • 在所有对对象判断是否为空的地方,直接调用isNull方法
      • 对空对象实现默认的空行为,这样可以不用判断是否为空,直接调用相应地函数(如果对象为空对象,那么会自动调用空行为)
      • 空对象可能会返回空对象
    • 引入断言增加代码可读性并且帮助调试

    对于简化条件表达式,我认为代码大全讲了更多地简化技巧

    Organizing Data

    这一章更多地是侧重于不同情况下组织数据的一些技巧

    • 将引用对象改为值对象值对象主要是不可变性,所以当确定一个引用对象不可变的时候,去掉setter方法,私有化成员变量,重写hashCode(集合类通过hashCode来快速定位对象的位置)和equals(来判断两者的地址是否相同)方法
    • 用类替代类型码,人的血型可以用类来进行封装p220(类型码不影响主类)
    • 用子类替代类型码,(类型码影响类的变化,可以用子类进行多态化处理,类的静态实例化函数通过类型码进行动态创建子类,子类实现抽象方法(getType)来返回正确地子类类型
    • 用state/strategy取代类型码实质跟多态取代子类相似

    Moving Features Between Objects

    核心就是如何抽象公共部分,较少冗余代码

    • move method:将公共方法提取至基类
    • move field
    • extra class(提炼类)
    • inline class (类内联化,将一个类的所有method和field都移入新的类)
    • hide delegate(隐藏委托关系) 在服务类建立客户所需的所有函数,用以隐藏委托关系Person Department Manager
    • remove middle man (移除中间人)(当客户端每次使用受托类的新特性的时候,都必须在服务端增加委托函数,所以新特性比较多得时候,客户端可以直接调用受托类
    • introduce foreign method 在客户类中建立一个函数,以第一参数形式传入一个服务类实例

    简化函数调用

    最重要的还是给函数和参数取一个好名字把

    • rename method
    • add parameter
    • remove parameter
    • 将查询函数和修改函数分离(任何有返回值的函数都不应该有side effect,不要使一个函数同时包含查询和修改)
    • preserve whole object(保持对象的完整性,不用传递多个参数,可以传递一个对象,保持代码的整洁性)
    • 以函数取代参数
    • 引入参数对象(都是为了缩短参数列长度)
    • remove setting method (某个字段设置为final的,不可改变)
    • hide method(当一个函数如果不被其他类引用时)
    • 以工厂函数取代构造函数
    • 封装向下转型
    • 以异常取代错误代码
    • 以测试取代异常

    处理继承关系

    这章侧重于如何处理子类和父类的field和method的关系

    • pull up field 字段上移
    • pull up method 函数上移
    • 构造函数本体上移
    • 函数下移
    • 字段下移
    • extract subclass 提炼子类
    • 提炼超类

    感想

    是个人都能写出让机器看懂的代码,但并不是所有人能写出其他人能看懂的代码,所以培养良好的代码风格是一件非常主要的事情,今后可能会遵守下面三条规则去规范自己培养良好的编码习惯

    • 注意函数命名,代码风格(各个语言参看对应系统库的代码风格),尽量写clean code
    • 在写代码之前,想好代码为什么这么写,这样写有什么好处,是否易于扩展,几个月之后自己是否还看得懂,别人是否看得懂
    • 找人code review,牛人对代码的认知以及整个项目的理解是跟自己不一样的,多问为什么这么设计以及这样设计的好处并思考这样设计的优缺点
    Contents
    1. 1. 何为重构
    2. 2. 重构的原动力
    3. 3. 何时重构
    4. 4. 重构方法
      1. 4.1. 简化条件表达式
      2. 4.2. Organizing Data
      3. 4.3. Moving Features Between Objects
      4. 4.4. 简化函数调用
      5. 4.5. 处理继承关系
  • 感想