重构——代码坏味道&重组函数.md

Posted Alex_MaHao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重构——代码坏味道&重组函数.md相关的知识,希望对你有一定的参考价值。

代码的坏味道

Duplicated Code ( 重复代码 )

如果你在一个以上的地点看到相同的程序结构,那么设法将它们合而唯一,程序会变得更好

最单纯的Duplicated Code 是同一个类的两个函数含有相同的表达式

另一种常见的情况分就是两个互为兄弟的子类内含相同的表达式

Long Method ( 过长函数 )

每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途命名(而非实现手法)。

如何确定该提炼哪一段代码呢?一个很好的技巧是:寻找注释。他们通常能指出代码用途和实现手法之间的语义距离。如果代码前方有一行注释,就是再提醒你:可以将这段代码换成一个函数,而且可以再注释的基础上给这个函数命名。就算只有一行代码,如果它需要以注释来说明,那也值得将它提炼到独立函数中。

Large Class ( 过大的类 )

Long Parameter List ( 过长参数列 )

通过以对象的成员变量,避免一个函数中参数过长。

Divergent Change ( 发散式变换 )

针对某一外界变化的所有相应修改,都只应该发生在单一类中,而这个新类内的所有内容都应该反应此变化。(适配器模式)

Shotgun Surgery ( 散弹式修改 )

如果每遇到某种变化,你都必须在许多不同的类内做出许多小修改。

这种情况应该把所有需要修改的代码放到同一个类中。

Divergent Change 是指 一个类受多种变化的影响,Shotgun Surgery 是指一个变化引发多个类相应的修改

Feature Envy ( 依赖情结 )

函数对某个类的兴趣高过对自己所处类的兴趣。例如某个函数为了计算某个值,从另一个对象那调用几乎半打的取值函数。

判断哪个类拥有最多被彼此函数使用的数据,然后就把这个函数和那些数据摆在一起。

Data Clumps ( 数据泥团 )

两个类中相同的字段,许多函数签名中参数相同

Primitive Obsession ( 基本类型偏执 )

通过一些基本类型的组装,拼装出一种小的数据类型。例如java中的String,Date等。

Switch Statements

面向对象程序的一个最明显的特征就是:少用switch语句。通过多态的概念来解决。

Paraller Inheritance Hierarchies (平行继承体系)

每当你为某个类增加一个子类,必须为另一个类相应增加一个子类。

Lazy Class

如果一个类的所得不值其身价,他就应该小时。

Temporary Field ( 令人迷惑的暂时字段 )

其内某个实例变量仅为某种特定情况而设定。

重构技巧

Extract Method ( 提炼函数 )

动机

当看见一个过长的函数或者一段需要注释才能让人理解用途的代码,我就会将这段代码放进一个独立函数中。

如果每个函数的粒度都很小,那么函数被复用的机会就更大。其次,这会使高层函数读起来就想一系列注释。再次,函数的复写也会更容易些。

Inline Method ( 内联函数 )

一个函数的本体与名称同样清楚一动

在函数的调用点插入函数本体,然后移除该函数。

Inline Temp ( 内联临时变量 )

你有一个临时变量,只被一个简单表达式赋值一次,而它妨碍了其他重构手法。

将所有对该变量的引用动作,替换为对它赋值的那个表达式自身

	double basePrice = anOrder.basePrice();
	return (basePrice > 10000);

to


return (anOrder.basePrice()) > 1000);

Replace Temp with Query ( 以查询取代临时变量 )

你的程序以一个临时变量保存某一表达式的运算结果

将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为新函数的调用。此后,新函数就可能被其他函数使用

double basePrice = _quantity * _itemPrice;
if (basePrice > 10000) 
	return basePrice * 0.95;
else 
	return basePrice 8 0.98;

to

if (basePrice() > 10000)
	return basePrice() * 0.95;
else 
	return basePrice() * 0.98;

double basePrice() 
	return _quantity * _itemPrice;

动机

临时变量的问题在于:它们是暂时的,而且只能在所属函数内使用。由于临时变量只在所属函数内可见,它们会驱使你写出更长的函数,因为只有这样你才能访问到需要的临时变量。如果把临时变量替换为一个查询,那么同一个类中所有函数都可以获得这份信息。

Introduce Explaining Variable ( 引入解释性变量 )

将复杂表达式的结果放进一个临时变量,以此变量名称来解释表达式用途。

if ((plathform.toUpperCase().indexOf("Mac") > -1)) 



to

final boolean isMacOs = plathform.toUpperCase().index("Mac") > -1;

Split Temporary Variable ( 分解临时变量 )

你的程序有某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果。

针对每次赋值,创造一个独立、对应的临时变量

动机

如果临时变量承担多个责任,它就应该被替换为多个临时变量,每个变量只承担一个责任。

Remove Assignments to Parameters ( 移除对参数的赋值 )

函数内对一个方法的参数进行赋值

以一个临时变量取代该参数的赋值

Replace Method with Method Object ( 以函数对象取代函数 )

将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后再这个对象中将大型函数分解为多个小型函数

Subsititute Algorithm ( 替换算法 )

换一种函数内逻辑写法。。。。

以上是关于重构——代码坏味道&重组函数.md的主要内容,如果未能解决你的问题,请参考以下文章

重构-坏代码的味道

重构的素养

重构:改善既有代码的设计读书笔记——开篇

我的重构识别代码的坏味道

重构—改善既有代码的设计3——代码的坏味道

学习重构-代码的坏味道