重构-读书笔记

作者: 手心里得温柔 | 来源:发表于2019-07-05 09:34 被阅读2次

    重构

    概念:在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。
    重构技术就是以微小的步伐修改程序。如果你犯下错误,很容易便可发现它。

    第一章 重构,第一个案列

    1. 何时重构:如果你发现自己需要为程序添加一个特性,而代码结构使你无法和方便的达成目的,那就先重构那个程序,使特性的添加比较容易进行,然后再添加特性。
    2. 重构的步骤
      • 第一个步骤永远相同:我得为即将修改的代码建立一组可靠的测试环境,这些测试必须有自我检验能力
      • 分解并重组
        1. 找出函数内的局部变量和参数,任何不会被修改的变量都可以被当成参数传入新的函数,如果只有一个变量会被修改,可以将他作为返回值。
        2. 去除临时变量
        3. 运用多态和继承

    第二章 重构原则

    1. 概念
      • 名词概念:对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
      • 动词概念:使用一系列重构手法,在不改变软件可观察行为的前提下,改变其结构。
    2. 重构的目的
      • 改进软件设计:消除重复代码
      • 使软件更容易理解:利用重构来协助理解不熟悉的代码,然后理解其用途,然后进行修改,使其能更好的反映出我的理解
      • 帮助找Bug:对代码进行重构,深入理解代码行为,做出假设。
      • 提高编程速度:良好的设计是快速开发的根本
    3. 什么时候重构
      • 三次法则:事不过三,三则重构(消除重复代码)
      • 添加新功能时:代码的设计无法帮助我轻松添加我所需要的新特性
      • 修补错误时
      • 复审代码时
      • 结论:我们希望程序长这样
        1. 容易阅读
        2. 所有逻辑都只在唯一地点指定
        3. 新的改动不会危及现有行为
        4. 尽可能简单表达条件逻辑
    4. 重构的难题:在重构时,应该实时掌握其过程,注意寻找可能引入的问题
      • 接口的修改:让旧接口调用新接口,留下旧函数,调用新函数。旧的接口或者函数可以使用Java自带的 @Deprecation注解。所以不要过早的发布接口,请修改你的代码所有权政策,使重构更顺畅
    5. 不应该重构:当代码实在太混乱的时候,可能重写比重构更有效,此时应该放弃重构

    第三章 代码坏味道

    1. 重复的代码:如果在一个以上的地点看到相同的程序结构,那么可以肯定,设法将他们合二为一,使程序变得更好
      • 同一个类的两个函数含有相同的表达式
      • 两个互为兄弟的子类含有相同的表达式,应该将其抽取并放到父类中
      • 如果两个毫不相关的类出现同样的代码,可以将重复代码提炼到一个独立的类中
    2. 函数体过长
    3. 类过大
    4. 参数列表过长:封装成对象来进行传递
    5. 异曲同工的类:应该重新思考其用途并重新命名。
    6. 过多的注释:当感觉需要些注释的时候,先尝试重构,让所有的注释都变得多余,尽量运用重构手法让我们不写注释。

    第四章 构筑测试体系

    • 测试的最终目的:确保所有的测试都完全自动化,让他们自己检查测试结果,一套测试就是一个强大的Bug侦测器,它能够极大的缩减找Bug的时间。
    • Junit测试:主要用来编写单元测试
      1. 频繁的运行测试,每次编译请把测试也考虑进去,每天至少执行每个测试一次
      2. 每当收到一个Bug报告,应当先写一个单元测试来暴露Bug
    • 单元测试和功能测试
      1. 单元测试:编写单元测试的目的是为了提高生产效率
      2. 功能测试:用于保证软件能正常运作。
    • 测试应该放在你最担心出错的部分,这样才能从中得到最大的利益
    • 考虑可能出错的边界条件,把测试火力集中在此
    • 总结:请构筑一个良好的Bug检测器并经常运行它,这对任何开发工作都大有裨益,并且是重构的前提

    第五章 重构列表

    1. 重构的记录格式
      • 名称:建造一个重构词汇表
      • 概要:简短的概要
        1. 用一句话介绍这个重构能帮我们解决的问题
        2. 一段简短陈述,介绍该做的事
        3. 一副速写图,展现重构前后实例
      • 动机:告诉你“为啥子需要这个重构”,还有什么情况下“不应该使用这个重构”
      • 做法:介绍如何一步一步的进行重构
      • 范例:用一个简单的例子说明该重构
    2. 重构的基本技巧:小步前进,频繁测试

    第六章 重新组织函数

    总体:重构手法

    1. Extract Method(提炼函数):把一段代码从原先的函数中提取出来,放到一个单独的函数中
      • 做法:
        1. 创造一个新函数,根据意图来命名(以它“做什么”来命名)
        2. 将被提炼代码中需要读取的局部变量,作为参数来传递
    2. Inline Method(内联函数):将一个函数调用的动作替换为函数本体
      • 做法:
        1. 检查函数,确定它不具有多态性(如果有子类来继承该函数,是不能做内联的)
        2. 找出该函数的所有被调用点
        3. 将这个函数的所有调用点都替换为函数的本体
    3. Inline Temp(内联临时变量):有一个临时变量,只被一个简单的表达式赋值了一次
      1. 检查给临时变量赋值的语句,确保等号右边的表达式没有副作用
      2. 如果该变量没有被声明为final类型,那么可以声明为final,然后编译,这样的目的是确保该变量是否真的被只赋值了一次
      3. 找到该变量的引用点,替换为临时变量的赋值表达式
    4. Replace Temp with Query(以查询取代临时变量):以临时变量保存表达式的结果
      • 做法:
        1. 找出只被赋值一次的变量
        2. 声明为final类型
        3. 将该临时变量右边的表达式提炼到一个函数中去
    5. Introduce Explain Variable(引入解释性变量):将复杂的表达式的结果放入一个临时变量来解释其用途
      • 做法:
        1. 声明一个final类型的临时变量,将待分解的复杂表达式中的一部分运算结果赋值给它
        2. 将表达式中的“运算结果”这一部分,替换为上述临时变量
    6. Split Temporary Variable(分解临时变量):针对每次赋值,创造一个独立,对应的临时变量
      • 做法:如果一个变量被赋值超过一次,意味着在函数中承担了一个以上的责任,那么就应该分解临时变量
        1. 在待分解临时变量的声明及第一次赋值处,修改其名称
        2. 为新的变量声明为final
        3. 以该临时变量的第二次赋值处为界,修改其所有的名称为新定义的变量
    7. Remove Assignments to Parameters(移除对参数的赋值)
      • 做法:
        1. 建立一个临时变量,把待处理的参数值赋予它
        2. 以对参数的赋值为界,将其后所有对此参数的引用点,全部替换为对临时变量的引用
        3. 修改赋值语句,使其改为对新建的临时变量赋值
    8. Replace Method with Method Object(以函数对象取代函数):将这个函数单独放到一个对象中,如此一来局部变量就成了成员变量,然后将这个大型函数分解为多个小型函数
      • 做法:
        1. 建立新类,根据待处理函数的用途来命名
        2. 在新类中建立一个原对象的final变量,用来保存原先大型函数所在的对象
        3. 建立大型函数中每个临时变量作为成员变量
    9. Substitute Algorithm(替换算法)
      • 做法:
        1. 准备好另一个算法,并使之通过编译
        2. 针对现有测试,执行上述算法。如果结果与原本结果相同,重构结束
        3. 如果不同,那么以旧算法为参考

    第七章 在对象之间搬移特性

    概念:在对象的设计过程中,“决定把责任放在哪儿”即使不是最重要的事情,也是最重要的事情之一”

    1. Move Method(搬移函数):在程序中,有个函数与其所驻类之外的类有更多的交流:调用后者,或者被后者调用。
    • 做法:在该函数最常引用的类中建立一个有着类似行为的函数。将旧函数变为单纯的委托函数,或是将就函数移除
      1. 检查源类中被源函数所使用的一切特性(包括字段和函数),考虑是否应该被搬移
      2. 检查源类中子类和超类是否有该函数的声明(多态性)。
      3. 在目标类中建立新函数,被搬移源函数的函数体
      4. 修改源函数,使之成为一个纯委托函数
    1. Move Filed(搬移字段):在程序中,某个字段被其所驻类之外的另一个类用得更多。
    • 做法:在目标类新建一个字段,修改源字段的所有用户,令他们改用新字段
      1. 如果该字段是public的,应该先进行封装起来
      2. 在目标类中建立相同的字段,并提供set/get方法
      3. 删除源中的字段
    1. Extract Class(提炼类):某个类做了应该由两个或多个类做的事情
    • 做法:建立一个新类,将相关的字段和函数提炼到新的类中
      1. 决定如何分解类的责任
      2. 建立一个新类,用于表现出旧类中分解出来的责任
      3. 建立两个类之间的访问连接关系
    1. Inline Class(将类内联化):类没有做太多事情。
    • 做法:将这个类中的所有特性搬移到另一个类中,然后移除源类
      1. 在目标类上什么源类的协议,将其中的所有函数委托至源类
      2. 修改所有源类的引用点,改为目标类的引用
      3. 运用Move Filed和Move Method将源类的变量和函数移动到目标类中
    1. Hide Delegate(隐藏“委托关系”):通过一个委托类来调用另一个对象
    • 做法:在服务的类上建立所需的所有函数,用以隐藏委托关系
      1. 对于每一个委托关系中的函数,在服务对象端建立一个简单的委托函数
      2. 修改为调用服务对象提供的函数

    相关文章

      网友评论

        本文标题:重构-读书笔记

        本文链接:https://www.haomeiwen.com/subject/sytshctx.html