好友
阅读权限 10
听众
最后登录 1970-1-1
象相合
发表于 2017-12-2 14:46
这篇文章整合了《重构-改善既有代码设计》2-4章的一些信息。主要有
1. 分析整理的重构原则。
2. 重构的手法场景介绍。
3. Junit测试的使用方式。
分享给大家,希望大家不要直接点收藏就关了,全部浏览一遍,可以在潜意识中酝酿这些大神们积淀多年的智慧。
有条件的同学,可以直接下载电子书 ,自己看一遍原本收获更多。
一、分析整理的重构原则。
为即将修改的代码建立一组可靠的测试环境。 临时变量助长冗长而复杂的函数。 最好不要再另一个对象的属性基础上运用switch语句。如果要switch也要在类自己的数据上使用。 事不过三,三则重构。 首先写出可调的程序,然后调整它以求获得足够速度。 一个好的名字可以省去读函数内容的操作。 每当需要注释说明时,可以被写进一个函数里,并以用途命名,关键不在函数长度,而在函数做什么,怎么做。 条件和循环也是提炼信号。 针对外界变化的所有相应修改,应该只发生在单一类中,这个类的所有内容随外界变化。 一个函数使用几个类的功能,它应该被放在最多被此函数使用的数据一起。 对于出现在不同类/方法内的一些绑在一起的数据,应该给它们设置对象。 少用switch,switch代表重复。 两个帽子原则:不要边写代码边重构,带上写代码的帽子,觉得需要重构了,再带上重构的帽子去做,如此反复。 注释多写为什么这样,过多注释不一定是好,尝试重构。 先编写测试代码可以将关注点放在接口而非实现。 每当出现一个BUG,先写一个测试单元测试BUG。不要修改以前的测试单元,因为它可能会在修复BUG后出错。 测试:异常,边界 测试太多带来的效益呈现递减态势。但是我们尽量测试大多数BUG。
二、重构的手法场景介绍。【由于IDE里使用的是英文,因此了解每一个英文意义尤为重要。 】
同一个类两个函数有相同表达式:Extract Method(110) 提炼相同代码。 互为兄弟子类内含有相同表达式:Extract Method(110) -> Pull Up Method(332) 推入超类 ->Form Template Method(345) 获得Template Method设计模式 -> Substitute Algorithm(139)替换算法。 毫不相关的类:Extract Class(149)
99%场合使用:Extract Method(110)找到适合在一起的提炼即可。 有大量参数和临时变量:Replace Temp with Query(120)消除临时变量,Introduce Parameter Object(295)和Preserve Whole Object(288)可将过长参数列变简洁。还不行就用Replace Method with Method Object(135)。 条件和循环时:Decompose Conditional(238)处理条件。Extract Method(110)处理循环。
类太大:Extract Class(149)甚至可以Extract Subclass(330)提取子类。先确定客户端如何使用他们,再运用Extract Interface(341)为每一个使用方式提炼一个接口。这可以帮助看清如何分解类。 如果是个GUI类:使用Duplicate Observed Data(189)。
如果向已有对象发出一条请求就可以取代一个参数,使用Replace Parameter with Method(292)。 使用Preserve Whole Object(288)将同一对象的数据收集起来,并以对象替换。 缺乏合理对象归属:使用Introduce Parameter Object(295)制造参数对象。
一个类受多个变化的影响:Extract Class(149)
每遇到一个变化,要在不同类做修改:Move Method(142)和Move Field(146)把需要修改的代码放进同一个类。使用Inline Class(154)把一系列相关行为放进一个类。
函数为了计算某个值,从另一个对象调用一堆取值函数:把这个使用Move Method(142)把它移到该去的地方。使用Extract Method(110)把这一部分提炼到独立函数,使用Move Method(142)放在该去的地方。如果有多个类的功能,使用Extract Method(110)分解为多个小函数,再放在调用最多数据的类里。
对于多个地方绑定在一起的数据:使用Extract FClass(149)将他们提炼到一个独立对象。然后转到函数签名,使用Introduce Parameter Object(295)或Preserve Whole Object(288)为他减肥。这样可以简化调用。
Primitive Obsession基本类型偏执
对象可以在小类型创建小对象:使用Replace Data Value with Object(175)进入对象世界。 替换的数据值是类型码,并不影响行为:使用Replace Type Code with Class(218) 与类型码相关的条件表达式:使用Replace Type Code with Subclass(213)或Replace Type Code wtih State/Strategy(227)处理。 总被放一起的字段:使用Extract Class(149) 参数列看到基本型数据:使用Introduce Parameter Object(295)。 从数组中挑选数据:使用Replace Array with Object(186)
Switch Statements:Switch惊悚现身
使用多态代替Switch:Extract Method(110)->Move Method(142)->Replace Type Code with Subclasses(223)或Replace Type Code with State/Strategy(227)完成继承结构->Replace Conditional with Polymorphism(255) 如果是单一函数的选择示例:使用Replace Parameter with Explicit Method(285) 如果选择条件有null:使用Introduce Null Object(260)
Parallel Inheritance Hierarchies平行继承体系
每当为某各类增加子类,也要为另一个类增加子类:让继承体系的实例引用另一个继承体系的实例。再使用Move Method(142)和Move Field(146)。
一个类变得不再有价值:使用Collapse Hierarchy(344)和Inline Class(154)。
Speculative Generality夸夸其谈未来性
对于未来可能会有的方法或类:如果它没被用到,使用Collapse Hierarchy(344)或Inline Class(154)。 某些参数未被使用:Remove Parameter(154) 函数名称有多余抽象意味:Rename Method(273)
某个实例变量仅因特定情况而设:使用Extract Class(149)提取这个情况并把相关代码放进去。也可以用Introduce Null Object(260)在“变量不合法”的情况创建Null对象。 复杂算法需要好几个变量:Extract Class(149)把这些变量和其他相关函数提炼到一个类作为函数对象Beck。
一个对象请求一个对象又请求一个对象…:使用Hide Delegate(157) 可以在消息链不同位置使用。更好的做法:Extract Class(149)提炼到一个函数,Move Method(142)推入消息链。
过度委托:使用Remove Middle Man(160)和负责的对象打交道。运用InlineMethod(117)放进调用端。如果Middle Man还有其他行为,使用Replace Delegation with Inheritance(355)变成实责对象子类,就可以扩展原对象行为。
Inappropriate Intimacy狎昵关系
两个类过去亲密:使用Move Method(142)和Move Field(146)划清界限。或使用Change Bidirectional Association to Unidirectional(200)让一个类斩断关系。Extract Class(146)提炼到一个安全地点。或使用Hide Delegate(157)
Alternative Classes with Different Interfaces异曲同工的类
两个函数做同一件事,却有不同签名。使用Rename Method(273)根据用途命名。使用Move Method(142)将某些行为移入类直到协议相同。使用Extract Superclass(336)可以减少重复冗余代码。
Incomplete Library Class不完美的库类
修改库类的函数:使用Introduce Foreign Method(162) 添加额外行为:使用Introduce Local Extension(164)
有一些用于访问(读写)字段的函数,其他类过分操作它们:使用Encapsulate Field(206)封装对不该被其他类修改的字段,使用Remove Setting Method(300)对这些点Move Method(142)把它们调到Data Class不能搬移整个就搬部分,不久就可以使用Hide Method(303)把它们隐藏。
继承设计错误:新建兄弟类,使用Push Down Method(328)和Push Down Field(329)把用不到的推给兄弟类。超类只持有所有子类共享的东西。 子类复用了超类行为,却又不愿意支持超类接口:使用Replace Inheritance with Delegation(352)达到目的。
太多注释意味着坏味道:使用Extract Method(110),还需要注释的话使用Rename Method(273),如果需要注释需求使用Introduce Assertion(267)
三、Junit测试的使用方式。
上github:https://github.com/EleComb/Reconstruction
如果你不知道github怎么用,看这里 或官方文档
OK,今天的分享就是这些了,祝大家学习进步!
免费评分
查看全部评分
发帖前要善用【论坛搜索 】 功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。