笔记的目的是方便自己查阅。
有些重构方法不在笔记中,可能是因为:
1、该方法在工作中已经熟练使用,不需要记录
2、该方法自己还不能灵活运用,需要再积累些经验
3、该方法自己并不认可(比如replace temp with query)
4、该方法在我的工作中不适用(比如适用于GUI的方法,现在都使用设计良好的框架)
第一章:重构,第一个案例
重构的时机:
重构第一步:测试环境
分解大函数,extract method
改变量名
move method:函数应该放在它所使用的数据的所属对象内。保险的做法,是保留旧函数,由旧函数调用新函数。
重构可能会牺牲性能。考虑重构+优化,而不是放弃重构
如果某个属性上有大量条件判断,考虑采用状态机或策略模式
第二章 重构原则
想清楚自己戴的哪顶帽子——重构时不改功能,改功能时不重构。开发过程中两件事常常交替进行。
第三章 代码的坏味道
坏味道:重复代码,长函数,大类,长参数列,发散式变化,。。。
当一段(甚至一行)代码,感觉需要注释来说明它干什么时,就可以extract,并用良好的函数名说明其用途。
局部变量过多,函数参数过长,类太多实例变量,都可以把相关变量提炼到一个对象中。
第六章 重新组织函数
这一章主要有两类内容:
1、extract method以易读性为指导原则
2、处理局部变量
6.5 introduce explaining variable:将复杂表达式的结果放入临时变量,变量名可以解释表达式的用途。该临时变量应声明为final。当这类局部变量较多时,使用introduce explaining variable;只有少数时使用extract method(但我个人不喜欢replace temp with query方法,所有无论使用哪种方式,如果表达式结果使用多次,都需要引入一个临时变量)。
6.8 replace method with method object: 大型函数,有很多局部变量。将大函数放入一个对象,局部变量作为对象字段,然后对大函数进行extract method
第七章 在对象之间搬移特性
随着系统发展,类容易变得越来越臃肿,承担太多责任,或责任不清晰。
7.1-7.2 move method/field:划清责任。
一个函数使用另一个对象的次数,比自己所驻对象的次数还多。某个字段被另一个类更多地用到。
7.5 hide delegate: 在服务对象中建立委托函数,而不是公开被委托对象。这样一单委托关系发生变化,改变和可以只在服务对象中处理,而不需要client知晓。
7.7-7.8 introduce foreign method / introduce local extension: 当需要为某个类添加特性,但无法修改这个类时:
如果只添加一两个特性,introduce foreign method,将这个类的实例作为意义参数传入foreign method,并用注释表明这是个foreign method;
如果添加多个特性,设计一个子类或包装类。(个人倾向于始终使用包装类或util类 。《effective java》中说“复合优于继承”)
第八章 重新组织数据
8.1 self encapsulate field: 即使在类内部,也使用get, set访问自己的属性。(有争议,可根据实际情况灵活运用)
8.2 replace data value with object: 如果一个数据项,需要和其他数据和行为一期使用才有意义。(比如,表示“订单”的类中,有“顾客姓名”,“顾客性别”两个字段,应该将它们替换成“顾客”对象)。
8.3 change value to reference : 使用工厂函数代替构造函数,对象可以预先创建好(比如Collections.EmptyList),或动态创建。
8.11 encapsulate collection : 取值函数不该返回集合自身,因为这会让用户得以修改集合的内容,而集合拥有者却一无所知。建议返回集合的只读副本,并提供公开的add, remove函数。
8.13 replace type code with class : 用类型类的静态实例代替基本类型的type code,并可能封装部分行为(例如获取类型的文字描述)。
8.14 replace type code with subclass: 不同类型的对象有不同行为,则一个类型是一个子类,避免复杂的条件判断。
8.15 replace type code with state/strategy: 如果对象的类型是可变的,就不能使用subclass。
第九章 简化条件表达式
9.1 decompose conditional : 将复杂的条件表达式提炼成bool函数(其实是一种extract method)
9.5 replace nested conditional with guard clauses: 前提是每个分枝都可以直接break或return。可以配合extract method将条件语句提炼成独立函数。
9.6 replace conditional with polymorphism
第十章 简化函数调用
这一章的关键在于,使接口更加容易理解和使用。
10.4 separate query from modifier : 一个get函数不应该有任何副作用。
10.5-10.6 parameterize method(to replace explicit methods)/ replace parameter with explicit methods : 关键在于函数的行为差异有多大
10.12 replace constructor with factory method:当创建对象时需要额外的动作
10.13 encapsulate downcast : 个人觉得这个说法太理想化了。重新解读为“在尽量低的层次上进行向下转型”。
第十一章 处理概括关系
概括关系(generalization) 即继承关系。
11.1-11.8 字段/函数上移/下移,提炼子类/超类/接口
11.11 replace inheritance with delegation :某个子类只使用超类接口或属性中的一部分(逻辑上并不属于超类的一个具体类型),改为委托关系。
11.12 replace delegation with inheritance : 存在大量简单的委托时。
第十二章 大型重构
重新梳理下这章的内容,将“方法列表”重新梳理为“场景——方法”结构。
12.2 当手上有太多过程化风格的代码时,需要convert procedural design to object。
综合使用replace data value with object,replace method with method object,extract method
12.4 extract hierarchy:其实就是replace conditional with polymorphism的大规模运用?