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