重构-改善既有代码的设计
2013-12-10 17:19
267 查看
JAVA按值传递,给参数赋值不会改变原值,但修改参数对象会改变原对象状态(引用)
值参数不可改
一个方法或类只承担一个职责。
目的清晰,说明明确,让人理解,一些潜规则,比如继承等
1.带来的问题:
某方法很难重用,一个相似功能就需要写一个新的方法,结果就是两个相似的方法存在,之后如果有改动,需要两个同时都改,越来越复杂
2.代码块越小,代码的功能就越容易管理,代码的处理和移动也就越轻松
3.每个函数粒度都很小,那么函数被复用的机会就更大,像注释
一.步骤:
1) 建测试环境
2) 分解并重组函数
a. 找出代码的逻辑泥团并提成一个新的方法:没被修改的作为参数传递,修改了的如果一个可以作为返回值
3)好的变量名是代码清晰的关键,好的代码应该清楚的表现自己的功能
4)绝大多数情况下,函数应该放在它所使用的数据的所属对象内, 修改原先引用
5) 尽量少的临时变量
6) switch 中的参数应该是本类中的属性。
二.原则:
1) 事不过三,三则重构
2) 增加中间层可以解决很多问题:
a.允许逻辑共享
b.分开解释意图和实现
c.隔离变化
d.封装条件逻辑
4.坏代码:
1) 重复代码: 提出成一个方法
a.子类有类似的方法: 提出到超类;如果是相似,则将变化与不变隔离
b. 两个不想关的类出现重复代码:将重复代码提炼成一个重复的类
2) 过长的函数:
a.小函数容易理解的真正关键在于一个好名字
b.每当感觉需要用注释说明时,把需要说明的东西写在一个独立函数中,并以其用途命名
c.循环和其内的代码提炼到一个独立函数中
3) 过大的类: 当利用单个类做太多事情,内部往往会出现太多实例变量
a.不是一直都用所有的实例变量: 提出几个相关的到新类中
b.太多代码: 先确定客户端如何使用它们,然后为某种方式提炼出一个接口
c.过长的参数列表: 将参数变成对象传过去(同时也会造成大对象和被调用对象的依赖关系)
4)针对于某一外界变化所有相应修改,都只应该发生在单一类中:一个变化需要修改多个类,一个类被多个变化影响
5)将数据和对数据的操作行为包装在一起,如果函数对某个类的兴趣大于自己所处的类,那么就移到那个类中。如果被几个类依赖,拆成小方法然后移到最多依赖的类中。 将总是一起变化的东西放在一起
6)当两个类中有相同的字段,许多函数签名中都有相同的参数。把他们提炼到一个独立的对象上: 删掉其中的一项,其余的是否会失去意义
三.重构方式:(132)
1.过长函数:
1) 提炼函数: 困难是处理局部变量
a.用意图去命名:做什么而非怎样做
b.原函数局部变量换成参数
c.只是该代码块内部用的设为局部变量
d.如果改变了原类的值,需要有返回值
2)以查询取代临时变量:临时变量在类的其它部分也需要,且该临时变量只被赋值一次(final)-->换成方法
3)引入解释型变量: 将该复杂表达式(或一部分)的结果放进一个临时变量,以变量名称来解释表达式用途
4)分解临时变量: 某个变量被赋值超过一次,把该变量拆成两个变量。每个临时变量只承担一个责任,用final试验
5) 移除对参数的赋值: 如果传的非对象,那么以一个临时变量取代该参数的位置,返回该临时变量
6) 面对一个大型函数,由于局部变量很多无法提出成小的方法,以函数对象取代函数:将这个函数变成一个对象,所有的临时变量为这个类的属性,这样就不用再传递参数,然后再提
四.在对象之间搬移特性:
1.搬移函数:使用另一个对象的次数比使用自己所驻对象的次数还多
2.提炼类:类的职责过多,提出子类
3.本地扩展,原类需要添加职责,所以建立新类,导入原有类,在新类中加新方法
4.以对象取代数据值: 有一个数据项,需要与其它数据和行为(方法)一起使用才有意义。197
5.以对象取代数组: 有一个数组,但其中的元素各自代表不同的东西:以对象替换数组。对于数组的每个元素,以一个字段来表示(意义更清晰)
6.以字面常量取代魔法数: 有一个字面数值,带有特别的含义:创造一个常量,根据其意义为它命名,并将上述的字面数值替换为这个常量
7.以子类取代类型码: 有不可变的类型码,影响类的行为(一个类中有多个同质的类型):以子类取代这个类型码(整体替代)/用策略模式替代(部分替代) -> 工厂
五.简化条件表达式:
1.分解条件表达式: if - else if -- ... -- else : 从if,else if,else三个段落中分别提炼出独立的函数 逻辑清晰,体现代码意图
2.合并条件表达式: 有一系列测试都得到相同的结果:用与或关于合成一个条件表达式,并将这个条件表达式提炼成一个独立函数(意思是一起的)
3.合并重复的条件片段: 在条件表达式的每个分支上都有着相同的一段代码:将这段重复的代码搬移到条件表达式之外.这样才能清晰的表现出哪些随条件的变化而变化,哪些东西保持不变
4.以卫语句取代嵌套表达式: 如果某个条件极为罕见,就应该提出来单独检查,而非if-else (告诉读者这个很罕见,不平等)
六.简化函数调用:
1. 函数改名: 给函数写上注释,然后把注释变成函数名(304)
2. 令函数携带参数 建立单一函数,以参数表达那些不同值 ---> 消去重复
3.保持对象完整: 从对象里取出若干值,将它们作为某一次函数调用时的参数 --->传递整个对象(因为有可能调用其它的值)
4.减少参数长度: 如果该函数参数由另一个函数获得,让该函数直接调用那个函数
5.引入参数对象:某些参数总是很自然地同时出现---->以一个对象取代这些参数,解决数据泥团
6.当一个函数没有被其它任何类用到,将这个函数设置为private
7.以异常取代错误码: 异常只用来处理意料之外的行为
七.处理概括关系
1.如果两个子类拥有相同的字段:将该字段移至超类
2.函数上移:某些函数在各个子类中产生完全相同的结果--->将该函数移至超类 (避免修改了一个没有修改另一个)
3.构造函数本地上移:子类中的构造函数有共通点--->在父类建造一个新的构造函数,在子类构造函数中调用它
4.塑造模板函数:子类中某些操作执行顺序相同,细节不同-->将这些操作分别放到独立函数中,起相同的函数签名,将原函数上移至超类
5.以委托取代继承:某子类只用超类一部分接口-->子类中添加超类引用属性,将继承改为委托
八.大型重构:384
1.某个继承体系同时承担两种责任:建立两个继承体系,并通过委托关系让一个调用另外一个
2.将过程化设计转化为对象设计:将数据记录变为对象,将大块行为分成小块,并将行为移入相关对象中
3.将领域和表述/显示分离: 将领域逻辑分离出来,为它们建立独立的领域类
4.提炼继承体系:建立继承体系,以一个子类表示一种特殊情况
值参数不可改
一个方法或类只承担一个职责。
目的清晰,说明明确,让人理解,一些潜规则,比如继承等
1.带来的问题:
某方法很难重用,一个相似功能就需要写一个新的方法,结果就是两个相似的方法存在,之后如果有改动,需要两个同时都改,越来越复杂
2.代码块越小,代码的功能就越容易管理,代码的处理和移动也就越轻松
3.每个函数粒度都很小,那么函数被复用的机会就更大,像注释
一.步骤:
1) 建测试环境
2) 分解并重组函数
a. 找出代码的逻辑泥团并提成一个新的方法:没被修改的作为参数传递,修改了的如果一个可以作为返回值
3)好的变量名是代码清晰的关键,好的代码应该清楚的表现自己的功能
4)绝大多数情况下,函数应该放在它所使用的数据的所属对象内, 修改原先引用
5) 尽量少的临时变量
6) switch 中的参数应该是本类中的属性。
二.原则:
1) 事不过三,三则重构
2) 增加中间层可以解决很多问题:
a.允许逻辑共享
b.分开解释意图和实现
c.隔离变化
d.封装条件逻辑
4.坏代码:
1) 重复代码: 提出成一个方法
a.子类有类似的方法: 提出到超类;如果是相似,则将变化与不变隔离
b. 两个不想关的类出现重复代码:将重复代码提炼成一个重复的类
2) 过长的函数:
a.小函数容易理解的真正关键在于一个好名字
b.每当感觉需要用注释说明时,把需要说明的东西写在一个独立函数中,并以其用途命名
c.循环和其内的代码提炼到一个独立函数中
3) 过大的类: 当利用单个类做太多事情,内部往往会出现太多实例变量
a.不是一直都用所有的实例变量: 提出几个相关的到新类中
b.太多代码: 先确定客户端如何使用它们,然后为某种方式提炼出一个接口
c.过长的参数列表: 将参数变成对象传过去(同时也会造成大对象和被调用对象的依赖关系)
4)针对于某一外界变化所有相应修改,都只应该发生在单一类中:一个变化需要修改多个类,一个类被多个变化影响
5)将数据和对数据的操作行为包装在一起,如果函数对某个类的兴趣大于自己所处的类,那么就移到那个类中。如果被几个类依赖,拆成小方法然后移到最多依赖的类中。 将总是一起变化的东西放在一起
6)当两个类中有相同的字段,许多函数签名中都有相同的参数。把他们提炼到一个独立的对象上: 删掉其中的一项,其余的是否会失去意义
三.重构方式:(132)
1.过长函数:
1) 提炼函数: 困难是处理局部变量
a.用意图去命名:做什么而非怎样做
b.原函数局部变量换成参数
c.只是该代码块内部用的设为局部变量
d.如果改变了原类的值,需要有返回值
2)以查询取代临时变量:临时变量在类的其它部分也需要,且该临时变量只被赋值一次(final)-->换成方法
3)引入解释型变量: 将该复杂表达式(或一部分)的结果放进一个临时变量,以变量名称来解释表达式用途
4)分解临时变量: 某个变量被赋值超过一次,把该变量拆成两个变量。每个临时变量只承担一个责任,用final试验
5) 移除对参数的赋值: 如果传的非对象,那么以一个临时变量取代该参数的位置,返回该临时变量
6) 面对一个大型函数,由于局部变量很多无法提出成小的方法,以函数对象取代函数:将这个函数变成一个对象,所有的临时变量为这个类的属性,这样就不用再传递参数,然后再提
四.在对象之间搬移特性:
1.搬移函数:使用另一个对象的次数比使用自己所驻对象的次数还多
2.提炼类:类的职责过多,提出子类
3.本地扩展,原类需要添加职责,所以建立新类,导入原有类,在新类中加新方法
4.以对象取代数据值: 有一个数据项,需要与其它数据和行为(方法)一起使用才有意义。197
5.以对象取代数组: 有一个数组,但其中的元素各自代表不同的东西:以对象替换数组。对于数组的每个元素,以一个字段来表示(意义更清晰)
6.以字面常量取代魔法数: 有一个字面数值,带有特别的含义:创造一个常量,根据其意义为它命名,并将上述的字面数值替换为这个常量
7.以子类取代类型码: 有不可变的类型码,影响类的行为(一个类中有多个同质的类型):以子类取代这个类型码(整体替代)/用策略模式替代(部分替代) -> 工厂
五.简化条件表达式:
1.分解条件表达式: if - else if -- ... -- else : 从if,else if,else三个段落中分别提炼出独立的函数 逻辑清晰,体现代码意图
2.合并条件表达式: 有一系列测试都得到相同的结果:用与或关于合成一个条件表达式,并将这个条件表达式提炼成一个独立函数(意思是一起的)
3.合并重复的条件片段: 在条件表达式的每个分支上都有着相同的一段代码:将这段重复的代码搬移到条件表达式之外.这样才能清晰的表现出哪些随条件的变化而变化,哪些东西保持不变
4.以卫语句取代嵌套表达式: 如果某个条件极为罕见,就应该提出来单独检查,而非if-else (告诉读者这个很罕见,不平等)
六.简化函数调用:
1. 函数改名: 给函数写上注释,然后把注释变成函数名(304)
2. 令函数携带参数 建立单一函数,以参数表达那些不同值 ---> 消去重复
3.保持对象完整: 从对象里取出若干值,将它们作为某一次函数调用时的参数 --->传递整个对象(因为有可能调用其它的值)
4.减少参数长度: 如果该函数参数由另一个函数获得,让该函数直接调用那个函数
5.引入参数对象:某些参数总是很自然地同时出现---->以一个对象取代这些参数,解决数据泥团
6.当一个函数没有被其它任何类用到,将这个函数设置为private
7.以异常取代错误码: 异常只用来处理意料之外的行为
七.处理概括关系
1.如果两个子类拥有相同的字段:将该字段移至超类
2.函数上移:某些函数在各个子类中产生完全相同的结果--->将该函数移至超类 (避免修改了一个没有修改另一个)
3.构造函数本地上移:子类中的构造函数有共通点--->在父类建造一个新的构造函数,在子类构造函数中调用它
4.塑造模板函数:子类中某些操作执行顺序相同,细节不同-->将这些操作分别放到独立函数中,起相同的函数签名,将原函数上移至超类
5.以委托取代继承:某子类只用超类一部分接口-->子类中添加超类引用属性,将继承改为委托
八.大型重构:384
1.某个继承体系同时承担两种责任:建立两个继承体系,并通过委托关系让一个调用另外一个
2.将过程化设计转化为对象设计:将数据记录变为对象,将大块行为分成小块,并将行为移入相关对象中
3.将领域和表述/显示分离: 将领域逻辑分离出来,为它们建立独立的领域类
4.提炼继承体系:建立继承体系,以一个子类表示一种特殊情况
相关文章推荐
- 重新组织数据(读书摘要——重构改善既有代码的设计)
- 《重构 改善既有代码的设计》——学习笔记(三)
- 【软件工程】重构-改善既有代码的设计
- 摘抄《重构-改善既有代码的设计》
- 重构-改善既有代码的设计(2.2)
- 『重构--改善既有代码的设计』读书笔记----Replace Temp with Query
- 重构――改善既有代码的设计
- 《重构 改善既有代码的设计》——学习笔记(二)
- 『重构--改善既有代码的设计』读书笔记---Duplicate Observed Data
- 重构-改善既有代码的设计
- 《重构 改善既有代码的设计》书摘
- 《重构-改善既有代码设计》读书笔记-重构篇
- 重构改善既有代码的设计--重新组织数据
- 重构:改善既有代码的设计(2)
- 读 《重构 : 改善既有代码的设计》
- 重构 改善既有代码的设计——重构列表
- 《重构-改善既有代码的设计》读书笔记
- 重构 改善既有代码的设计(读书笔记2)
- PHP 杂谈《重构-改善既有代码的设计》之二 对象之间搬移特性
- 《重构--改善既有代码的设计》读书笔记之一:起始代码之C++ Version