资讯专栏INFORMATION COLUMN

读书笔记《重构 改善既有代码的设计》

mdluo / 2077人阅读

摘要:重构在不改变代码的外在的行为的前提下对代码进行修改最大限度的减少错误的几率本质上,就是代码写好之后修改它的设计。重构可以深入理解代码并且帮助找到。同时重构可以减少引入的机率,方便日后扩展。平行继承目的在于消除类之间的重复代码。

重构 (refactoring) 在不改变代码的外在的行为的前提下 对代码进行修改最大限度的减少错误的几率 本质上, 就是代码写好之后 修改它的设计。

1,书中开始用一个例子简单阐释为什么要重构,以及重构的好处

- 如果没有重构,程序就会腐败变质,程序逐渐失去自己的结构,

 越来越难通过读源码理解设计,不良重复的代码不便于后来的修改和阅读。

- 重构可以深入理解代码并且帮助找到bug。

    同时重构可以减少bug引入的机率,方便日后扩展。提高可理解性,
    降低修改成本。

- 提高编程的速度,良好的设计师快速开发的根本(阻止代码腐败,

 提高质量,从而提高开发速度)。
 sum:容易阅读,所有逻辑都只在唯一的地点指定,新的改动不会影响过去的功能,
 尽可能的表达条件逻辑。

----------

1.2,重构的第一步就是建立一个有效的测试机制,好的测试机制可以帮助重构

1.3,针对案例中的customer类的函数statement进行分析,这个函数太长,需要分解,拆分,因为简单的代码块容易管理。
作者将这个statement函数里面的根据电影的类型返回不同的价格的方法,提炼出来,代码简洁易懂
关于函数的名称的命名,作者总结道,只有写出人类容易理解的代码 才是优秀的代码。

函数位置:函数应该放在它使用的数据的所属对象内,所以作者举例说明那个customer中的statement函数根据不同类的作用做了拆分,比如获取电影的价钱和积分数放在租赁类中,获取总电影价以及总积分放在Customer类中,这样逻辑清晰。

2,重构原则

 2.1,什么时候重构
   - 添加新功能是重构 
   - 修复bug时重构 
   - 评审代码是重构(结对编程)

重构小技巧:

  - 允许逻辑共享 
  - 分开解释意图或实现 
  - 隔离变化 例如一个类需要在2个地方使用,可以使用子类来处理变化 4)封装条件逻辑
  
2.2, 重构与设计
  前提简单可行的设计(不一定要完全正确), 重构可以预先取代设计,先把功能做好 然后重构 “极限编程” 支持这种观点,证明这种方法可行
 2.3,重构与性能
   时间预算 持续关注法(深度理解代码,并且知道哪些地方耗费时间)
   性能优化案例:
   大字符串操作耗费性能?
   字符串缓存起来 - 改用文件流处理 - 多处理器计算机,多线程 系统从运算1000个小时 到 2个小时的飞速提升
   

3,代码坏味道

重复代码
 - 同一个类 2个函数有相同的表达式 
 - 兄弟子类有相同的表达式 
 - 2个独立的类有相同的代码
3.2 函数过长
  分解函数的原则:每当感觉需要注释说明点什么的时候,我们需要把需要说明的东西写到一个独立的函数中,并以其用途来命名。如果代码前面有一条注释,就说明这个地方需要提炼出一个函数。

  条件表达式(多个if else 改成三元表达式 Decompose Conditional) 和循环也是提炼的信号,
  循环可以提炼到一个多带带的函数中。

 3.3 过大的类 --解决重复代码的问题
 3.4 过长的参数列,建议使用参数对象,传递一个参数。
 3.5 发散式变化(一个类受到多种变化的影响),散弹式修改 一个变化引发多个类修改
 解决经常被修改的类,将经常需要修改的变量字段提炼到一个独立的类。

 3.6 依恋情节 数据和数据操作包装在一起 原则:将总是一起发生变化的东西放在一起。
 3.7 数据泥团 类中有相同的属性 函数中有类似的参数 删除一个不影响这个类或者函数的意义,建议拆分新对象 减少字段或者参数的个数
 3.8,switch statement
  大多情况下 出现switch语句 就应该考虑多态来替换,这样的switch需要提炼到一个独立的函数并且将它放到需要处理的类中。
 3.9 平行继承 目的在于消除类之间的重复代码。
 3.10 冗赘类 无用的代码类。
 3.11 暂时使用的字段 只有执行某个代码块才有意义的字段  抽到一个独立的类中
 3.12 过多的注释 试图用函数提炼代码,删除注释

4,构建测试体系

意义:一套测试就是一个强大的bug监听器 能够大大减少bug查找时间
建立一个独立的类用于测试并且在框架中运用它,使测试工作更加轻松
4.1 Junit 测试框架的运用
每收到一个bug,先写一个单元测试来暴露bug,考虑可能出错的边界条件,把测试的重点集中在那

5 重构列表
6.重构函数

重构的大部分集中在函数的重构,参数的重构
 内联函数 去除间接层
1,不要对参数赋值(Java 1.1 允许将参数定义为final)。 
2,如果临时变量被多次赋值,应该分解多个独立的临时变量 
3,分析临时变量是否被公用,把这个临时变量提炼到一个函数中(Replace temp with query) 
4,临时变量用于分解复杂的表达式 
5,替换算法,将比较复杂的算法替换成简单的 易懂的(或者将大的算法分成小部分 易于理解,然后寻找小算法的替换方案)

7,对象之间的搬移特性

1,函数搬移 -- 一个类函数过多 或者 函数依赖的类比较多 考虑这个函数与哪个类接触较多来决定搬移路径。
2,字段搬移 -- 随着业务的发展,发现一个类中的一个字段被多个函数或者类共同使用,考虑搬移这个字段或者可见度的改变(将这个字段变成public)
3,提炼类 -- 随着业务的发展 一个类中有太多的函数和字段 考虑把类似的字段和函数搬移出去。
4,内联化 -- 将一些不独立承担任务的类塞到另外一个独立类中,这种类称为萎缩类。
5, 委托关系,简单理解为封装函数,便于日后修改变得容易。

8,重新组织数据

1,自封装字段 简单理解就是将这个字段需要转换的值通过函数的方式表达 getBussinessVal();
2,以对象取代数据值 一个字段存在多种数据与行为一起使用才有意义时 建议将字段变成对象。
3,将值对象(数值)变成引用用对象(物体) 同一个对象被多个其他的类同时用到,比如 数据库连接,这个时候我们用工厂模式 进行复用来重构。
4,以对象取代数组, 方便用户记忆
5,将系统的魔法数定义为常量 static  final double WEIGHT_CONSTANT = 9.18;
6, 封装字段,将行为和意义类似的字段封装起来定义为private 提供public的访问函数
7,封装对象关联的集合,和数组  根据业务逻辑封装 list.add 改为emp.addEmp(); 将类似操作对象的集合统一集中到这个类中
8,运用多态继承取代switch,将涉及到switch的类型码判断 统一移动对象类里面处理
9,子类中不应该有常量 如果有在超类中申明抽象类 在子类实现 返回不同值

9,简化条件表达式

1,分解合并条件表达式 - 利用函数的方法 将多个判断条件根据业务逻辑封装成独立函数,用功能目的来命名,然后调用函数判断 例如 if (notData(params)){...} else {...}
2,合并上下重复的条件判断
3,循环逻辑用break 和 return 取代控制指标 比如 while(a

10,简化函数调用
1,修改函数的名称 -- 首先考虑给这个函数写上一句怎样的注释,然后想办法将注释变成函数的名称
2,将查询函数和修改函数分离 如果发现一个函数有返回值又有副作用的函数 优化方法,将查询到的值缓存到某个字段中,这样后续的查询就可以加快速度
3,将2个类似的函数 通过函数合并 减少代码量
4,保持函数参数传递的对象完整 比如 in a = sumANums(b).getM(); 直接传递真个对象 plan.setCountNums(sumANums(b));
5, 尽量减少参数个数,建议传递一个对象作为参数
6,将一些经常一起传递的参数作为一个参数对象传递
7,移除设值函数,发现系统中有一个字段初始化被赋值一次然后一直不变 移除这个字段,并且直接修改这个字段为final
8,隐藏函数,更加这个函数是否被调用的次数判断是否设置某些值为private 和 public,尽可能的降低函数的可见度
9,以工厂函数取代构造函数 解决switch的类型码的判断

 例如:private int _type; static final int A = 1; static final int B = 2;
Employee(int type) {_type = type;}static Employee create(int type) { return new Employee(type)}

11, 处理概括关系

1,字段上移 两个类拥有相同的字段 将该字段移至超类
2,函数上移,两个函数,在各个子类中产生完全相同的结果,将该函数移至超类
3,构造函数上移,在子类的构造函数中调用它
4,函数、字段下移,相反
5,提炼接口,将两个接口相同的子集提炼到一个独立的接口中
6,以委托取代继承 随着义务的发展 超类中的一些函数你不需要,这时需要新建一个子类委托继承你需要的函数,然后再继承你需要的类

12,大型重构 关于继承的重构
13,重构 复用与现实

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67924.html

相关文章

  • 重构-改善既有代码设计读书笔记-重构

    摘要:重构改善既有代码设计动词使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。修补错误时重构代码时重构怎么重构关于代码的重构技巧参考重构改善既有代码设计读书笔记代码篇个人博客 重构定义 名词 对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。——《重构-改善既有代码设计》 动词 使用一系列重构手法,在不改变软件可观察行为的前提下,...

    ermaoL 评论0 收藏0
  • Java学习路线总结,搬砖工逆袭Java架构师(全网最强)

    摘要:哪吒社区技能树打卡打卡贴函数式接口简介领域优质创作者哪吒公众号作者架构师奋斗者扫描主页左侧二维码,加入群聊,一起学习一起进步欢迎点赞收藏留言前情提要无意间听到领导们的谈话,现在公司的现状是码农太多,但能独立带队的人太少,简而言之,不缺干 ? 哪吒社区Java技能树打卡 【打卡贴 day2...

    Scorpion 评论0 收藏0
  • 重构-改善既有代码设计(五)--重构列表

    摘要:什么是重构列表重构方法需要以一种特定的格式记录下来。这些重构手法到底有多成熟本书中提到的重构手法第章。做法创造新函数,以用途命名提炼代码到函数中检查变量名是否符合规范在源函数中,将被提炼代码替换为函数引用测试范例重构前重构后 什么是重构列表 重构方法需要以一种特定的格式记录下来。按照格式记录下来的重构方法的集合叫重构列表 重构的记录格式 每个重构手法可分为5个部分: 名称 构建重构词汇...

    davidac 评论0 收藏0
  • 重构-改善既有代码设计(二) --重构原则

    摘要:改进代码设计的一个重要原则就是消除重复代码使软件更容易被理解优秀的代码能够让接收你代码的付出更少的学习成本。重构更容易找到重构能加深对代码的理解。可以重构的情况添加功能时可以重构。说明你没有发现代码的错误。需要重构复审代码时可以重构。 为何重构 重构不是银弹,但是帮助你达到以下几个目的 改进软件设计 不良的程序需要更多的代码。而代码越多,正确的修改就越困难。改进代码设计的一个重要原则就...

    myshell 评论0 收藏0
  • 《java 8 实战》读书笔记 -第八章 重构、测试和调试

    摘要:通常,这种模式是通过定义一个代表处理对象的抽象类来实现的,在抽象类中会定义一个字段来记录后续对象。工厂模式使用表达式第章中,我们已经知道可以像引用方法一样引用构造函数。 一、为改善可读性和灵活性重构代码 1.改善代码的可读性 Java 8的新特性也可以帮助提升代码的可读性: 使用Java 8,你可以减少冗长的代码,让代码更易于理解 通过方法引用和Stream API,你的代码会变得更...

    gclove 评论0 收藏0

发表评论

0条评论

mdluo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<