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

重构 (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

4,使用简单的if else 来判断逻辑,如果出现简单的if else 不能判断的,用独立的函数独立封装解决

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,重构 复用与现实

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1章 重构,第一个案例 1 1.1 起点 1 1.2 重构的第一步 7 1.3 分解并重组statement() 8 1.4 运用多态取代与价格相关的条件逻辑 34 1.5 结语 52 第2章 重构原则 53 2.1 何谓重构 53 2.2 为何重构 55 2.3 何时重构 57 2.4 怎么对经理说 60 2.5 重构的难题 62 2.6 重构设计 66 2.7 重构与性能 69 2.8 重构起源何处 71 第3章 代码的坏味道 75 3.1 Duplicated Code(重复代码) 76 3.2 Long Method(过长函数) 76 3.3 Large Class(过大的类) 78 3.4 Long Parameter List(过长参数列) 78 3.5 Divergent Change(发散式变化) 79 3.6 Shotgun Surgery(霰弹式修改) 80 3.7 Feature Envy(依恋情结) 80 3.8 Data Clumps(数据泥团) 81 3.9 Primitive Obsession(基本类型偏执) 81 3.10 Switch Statements(switch惊悚现身) 82 3.11 Parallel InheritanceHierarchies(平行继承体系) 83 3.12 Lazy Class(冗赘类) 83 3.13 Speculative Generality(夸夸其谈未来性) 83 3.14 Temporary Field(令人迷惑的暂时字段) 84 3.15 Message Chains(过度耦合的消息链) 84 3.16 Middle Man(中间人) 85 3.17 Inappropriate Intimacy(狎昵关系) 85 3.18 Alternative Classes with Different Interfaces(异曲同工的类) 85 3.19 Incomplete Library Class(不完美的库类) 86 3.20 Data Class(纯稚的数据类) 86 3.21 Refused Bequest(被拒绝的遗赠) 87 3.22 Comments(过多的注释) 87 第4章 构筑测试体系 89 4.1 自测试代码的价值 89 4.2 JUnit测试框架 91 4.3 添加更多测试 97 第5章 重构列表 103 5.1 重构的记录格式 103 5.2 寻找引用点 105 5.3 这些重构手法有多成熟 106 第6章 重新组织函数 109 6.1 Extract Method(提炼函数) 110 6.2 Inline Method(内联函数) 117 6.3 Inline Temp(内联临时变量) 119 6.4 Replace Temp with Query(以查询取代临时变量) 120 6.5 Introduce Explaining Variable(引入解释性变量) 124 6.6 Split Temporary Variable(分解临时变量) 128 6.7 Remove Assignments to Parameters(移除对参数的赋值) 131 6.8 Replace Method with Method Object(以函数对象取代函数) 135 6.9 Substitute Algorithm(替换算法) 139 第7章 在对象之间搬移特性 141 7.1 Move Method(搬移函数) 142 7.2 Move Field(搬移字段) 146 7.3 Extract Class(提炼类) 149 7.4 Inline Class(将类内联化) 154 7.5 Hide Delegate(隐藏“委托关系”) 157 7.6 Remove Middle Man(移除中间人) 160 7.7 Introduce Foreign Method(引入外加函数) 162 7.8 Introduce Local Extension(引入本地扩展) 164 第8章 重新组织数据 169 8.1 Self Encapsulate Field(自封装字段) 171 8.2 Replace Data Value with Object(以对象取代数据值) 175 8.3 Change Value to Reference(将值对象改为引用对象) 179 8.4 Change Reference to Value(将引用对象改为值对象) 183 8.5 Replace Array with Object(以对象取代数组) 186 8.6 Duplicate Observed Data(复制“被监视数据”) 189 8.7 Change Unidirectional Association to Bidirectional(将单向关联改为双向关联) 197 8.8 Change Bidirectional Association to Unidirectional(将双向关联改为单向关联) 200 8.9 Replace Magic Number with Symbolic Constant(以字面常量取代魔法数) 204 8.10 Encapsulate Field(封装字段) 206 8.11 Encapsulate Collection(封装集合) 208 8.12 Replace Record with Data Class(以数据类取代记录) 217 8.13 Replace Type Code with Class(以类取代类型码) 218 8.14 Replace Type Code with Subclasses(以子类取代类型码) 223 8.15 Replace Type Code with State/Strategy(以State/Strategy取代类型码) 227 8.16 Replace Subclass with Fields(以字段取代子类) 232 第9章 简化条件表达式 237 9.1 Decompose Conditional(分解条件表达式) 238 9.2 Consolidate Conditional Expression(合并条件表达式) 240 9.3 Consolidate Duplicate Conditional Fragments(合并重复的条件片段) 243 9.4 Remove Control Flag(移除控制标记) 245 9.5 Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件表达式) 250 9.6 Replace Conditional with Polymorphism(以多态取代条件表达式) 255 9.7 Introduce Null Object(引入Null对象) 260 9.8 Introduce Assertion(引入断言) 267 第10章 简化函数调用 271 10.1 Rename Method(函数改名) 273 10.2 Add Parameter(添加参数) 275 10.3 Remove Parameter(移除参数) 277 10.4 Separate Query from Modifier(将查询函数和修改函数分离) 279 10.5 Parameterize Method(令函数携带参数) 283 10.6 Replace Parameter with Explicit Methods(以明确函数取代参数) 285 10.7 Preserve Whole Object(保持对象完整) 288 10.8 Replace Parameter with Methods(以函数取代参数) 292 10.9 Introduce Parameter Object(引入参数对象) 295 10.10 Remove Setting Method(移除设值函数) 300 10.11 Hide Method(隐藏函数) 303 10.12 Replace Constructor with Factory Method(以工厂函数取代构造函数) 304 10.13 Encapsulate Downcast(封装向下转型) 308 10.14 Replace Error Code with Exception(以异常取代错误码) 310 10.15 Replace Exception with Test(以测试取代异常) 315 第11章 处理概括关系 319 11.1 Pull Up Field(字段上移) 320 11.2 Pull Up Method(函数上移) 322 11.3 Pull Up Constructor Body(构造函数本体上移) 325 11.4 Push Down Method(函数下移) 328 11.5 Push Down Field(字段下移) 329 11.6 Extract Subclass(提炼子类) 330 11.7 Extract Superclass(提炼超类) 336 11.8 Extract Interface(提炼接口) 341 11.9 Collapse Hierarchy(折叠继承体系) 344 11.10 Form Tem Plate Method(塑造模板函数) 345 11.11 Replace Inheritance with Delegation(以委托取代继承) 352 11.12 Replace Delegation with Inheritance(以继承取代委托) 355 第12章 大型重构 359 12.1 Tease Apart Inheritance(梳理并分解继承体系) 362 12.2 Convert Procedural Design to Objects(将过程化设计转化为对象设计) 368 12.3 Separate Domain from Presentation(将领域和表述/显示分离) 370 12.4 Extract Hierarchy(提炼继承体系) 375 第13章 重构,复用与现实 379 13.1 现实的检验 380 13.2 为什么开发者不愿意重构他们的程序 381 13.3 再论现实的检验 394 13.4 重构的资源和参考资料 394 13.5 从重构联想到软件复用和技术传播 395 13.6 小结 397 13.7 参考文献 397 第14章 重构工具 401 14.1 使用工具进行重构 401 14.2 重构工具的技术标准 403 14.3 重构工具的实用标准 405 14.4 小结 407 第15章 总结 409

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值