重构
2023-09-13 10:53:09 0 举报
重构改善既有代码设计总结
作者其他创作
大纲/内容
臭味示例
香味示例
提取重复代码让两个地方调用同一个方法
同一个类的两个函数含有相同的表达式
提取重复代码,并将重复代码推送到超类中
两个互为兄弟的子类包含相同的表达式
提取重复代码,并将重复代码推入新类或应该属于的类中
两个毫不相关的类出现相同的表达式
重复代码(98)
一般根据注释提取方法,将大方法分解为一个个的小方法
一个方法有几百行甚至上千行
过长函数(98)
提取部分变量到新类中
一个类拥有过多的实例变量或方法
确定客户端如何使用它们,然后为每一种方式提炼接口,再确定哪些方法可以移到其他类或新类中去
一个类拥有过多方法
过大的类(100)
将参数提取到对象中,以对象传参
方法参数过多
过长参数列(100)
将不同原因产生的变化函数分解到不同的类中
某个类因为不同原因在不同的方向上需要修改
发散式变化(101)
通过移动方法和变量放到同一个类
如果每遇到变化需要到许多不同类内进行小修改
霰弹式修改
把受依恋之苦的代码提取独立方法,然后移动方法到它该去的地方
函数对某个类的兴趣超过自己类的兴趣
依恋情节
类似DDD中的值对象,应该将这些字段提取出来作为值对象
相同的字段总是结对出现在不同的类中或方法参数中
数据泥团
将它们提取为对象,例如我们分页查询的Page对象,开始日期,结束日期也可以提取为日期查询对象
几个紧密关联的字段总是共同出现在不同的地方
基本类型偏执
先将swith语句提取到独立方法,然后再考虑用多态将case中的语句提取方法到多态实现类中
在面向对象中一般不应该允许switch出现
switch声明
让一个类的继承体系引用另一个类的实例
每当你为某个类增加一个子类,必须也为另一个类增加相应的子类,并且这两个类前缀相同
平行继承体系
干掉它吧
对于由于某种原因导致没啥价值的类
冗赘类
将来可能会用到的处理逻辑
夸夸其谈未来性
将其提取到单独的类中去
如果是多个实例变量和算法,那么将它们都提取出来到一个新类中去
某个实例变量只为某种特殊情况而设置的
令人迷惑的暂时字段
将消息链这段代码提取函数
向一个对象请求另外一个对象,然后又从另外一个对象请求另外一个对象
过度耦合的消息链
过度委托
中间人
使用搬移方法和实例为它们划清界限
或者提取一个新类将共同点放入到新类中
两个类过于亲密
狎昵关系
通过搬移方法或提取新类直到两者协议一致为止
两个函数做着相同的事,却有着不同的签名
异曲同工的类
不完美的库类
这种数据类需要封装起来,慎重被不应该set的地方改变其值
只拥有get/setter的数据实体类
纯稚的数据类
传统做法:为子类新建一个兄弟类,将不想继承的函数推给兄弟类
replace inheritence with delegation
子类不想继承父类某些函数
被拒绝的遗赠
1. 提取需要注释的那段代码到独立函数
2. 让函数名能够望名生意
函数中需要过多注释解释
过多的注释
代码坏味道
将一段可以组织在一起的代码提取出来作为一个独立方法
详解
提取方法(extract method)
当某些函数其内部代码和函数名称同样清晰易懂,那就应该去掉这个函数,直接使用其内部代码
将函数内联化(inline method)
将只被赋值一次的临时变量替换为为它赋值的表达式本身
将临时变量内联化(inline temp)
将只被赋值一次的临时变量提取为方法
详情
以查询取代临时变量(replace temp with query)
将一个复杂的表达式的结果放入一个临时变量,以此变量名称解释表达用图
引入解释性变量
如果临时变量承担多个责任,它就应该被替换(剖 解)为多个临时变量,每个变量只承担一个责任
剖解临时变量
如果你的代码对一个参数赋值,那就应该先用一个临时变量指向它,去对临时变量赋值
移除对参数的赋值动作
如果一个函数之中局部变量泛滥成灾,那你就应该把这个函数提取为一个类,然后再拆解该函数为多个小函数
以函数对象取代函数(Replace Method with Method Object)
把某个算法替换为另一个更清晰的算法
替换你的算法
重新组织函数
如果一个class有太多行为,或如果一个class与另一个class有太多合作而形成高度耦合(highly coupled),我就会搬移函数
搬移函数(move method)
如果我发现,对于一个field(值域),在其所驻class之外的另一个class中有更多函数使用了它,我就会考虑搬移这个field
搬移值域Move Field
提炼类(ExtractClass)
如果你的某个class没有做太多事情(没有承担足够责任),将class的所有特性搬移到另一个class中,然后移除原class。
将类内联化(InlineClass)
如果A调用B获得C,再调用C的某个函数,就应该把调用C的某个函数或对象的过程直接通过B来委托执行。
隐藏「委托关系」(HideDelegate)
移除中间人(RemoveMiddleMan)
如果你需要某个class提供一两个额外函数,但你无法修改这个class。那就在调用方直接提供编写该函数,并以该class作为第一个参数传入
引入外加函数(IntroduceForeignMethod)
你所使用的serverclass需要一些(超过两个)额外函数,但你无法修改这个class。建立一个新class,使它包含这些额外函数。让这个扩展品成为sourceclass的subclass(子类〕或wrapper(外覆类)。
引入本地扩展(IntroduceLocalExtension)
在对象之间搬移特性
如果你想访问superclass中的一个值域,却又想在subclass中将「对这个变量的访问」改为一个计算后的值,那就就取值封装为一个取值函数
自封装值域(SelfEncapsulateField)
你有一笔数据项(dataitem),需要额外的数据和行为。将这笔数据项变成一个对象
以对象取代数据值(ReplaceDataValuewithObject)
将实值对象改为引用对象(ChangeValuetoReference)
你有一个referenceobject(引用对象),很小且不可变(immutable),而且不易管理。将它变成一个valueobject(实值对象)
将引用对象改为实值对象(ChangeReferenceToValue)
你有一个数组(array),其中的元素各自代表不同的东西。以对象替换数组。对于数组中的每个元素,以一个值域表示之。
以对象取代数组(ReplaceArraywithObject)
两个classes都需要使用对方特性,但其间只有一条单向连接(one-way link)。添加一个反向指针,并使修改函数(modifiers)能够同时更新两条连接。
将单向关联改为双向
两个鄉之间有双向关联,但其中一个class如今不再需要另一个class的特性。去除不必要的关联
将双向关联改为单向
你有一个字面数值(literal number ),带有特别含义。例如折扣。创造一个常量,根据其意义为它命名,并将上述的字面数值替换为这个常量。
以符号常量/字面常量取代魔法数
你的class中存在一个public值域。将它声明为private,并提供相应的访问函数(accessors)
封装值域
重新组织数据
重构
0 条评论
回复 删除
下一页