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