重构-改善代码的既有设计-代码的坏味道(1)

版权声明:不自见故明;不自是故彰;不自伐故有功;不自矜故长; https://blog.csdn.net/LightUpHeaven/article/details/84494325

3.1.重复代码(Duplicated Code)

Extract Method, Form Template Method,Substitute Algorithm,Extract Class.

同一个类的两个函数含有相同的表达式,这时只需要从用Extract Method提炼出重复的代码,然后让这两个地点都调用被提炼出来的那一段代码。

两个互为兄弟的子类内含有相同表达式。要避免这种情况,只需对两个类都使用Extract Method,然后再对被提炼出的代码使用Pull Up Method,将它推入超类内。如果代码之间只是类似,并非完全相同,那么就得使用Extract Method将相似的部分和差异部分割开,构成单独一个函数。然后你可能发现可以运用Form Template Method获得一个Template Method设计模式。如果有些函数以不同的算法做相同的事,你可以选择其中比较清晰的一个,并使用Substitute Algorithm将其他函数的算法替换掉。

如果两个毫不相关的类出现重复代码,应该考虑对其中一个使用Extract Class将代码提炼到一个独立类中,然后在另一个类内使用这个新类。

3.2.过长函数(Long Method)Extract Method,Replace Temp with Query,Introduce Parameter Object,Preserver Whole Object.Replace Method with Method Object.

3.3.过大的类(Large Class)Extract Class(提炼至新类)。Extract Subclass(提炼至子类)。一个类如果有太多代码有个技巧:先确定客户端如何使用它们,然后运用Extract Interface为每一种使用方式提炼出一个接口。这可以帮助你看清楚如何分解这个类。

3.4.过长参数列(Long Parameter List)Replace Parameter with Method。Preserver Whole Object(一堆数据来自同一对象),Introduce Parameter Object(制造一个“参数对象”)。

3.5.发散式变化(Divergent Change)一个类受多种变化的影响。如果某个类总因为不同的原因在不同的方向上发生变化,就会缠身Divergent Change。针对某一外界变化的所有响应修改,都只应该发生在单一类中,而这个类中所有内容都应该反映此变化,然后运用Extract Class将它们提炼至另一个类中。

3.6.霰弹式修改(Shotgun Surgery) 一个变化需要引发多个类响应修改。如果需要修改的代码散布四处,你不但很难找到它们,也很容易忘记某个重要的修改。此时应使用Move Method,Move Field把所有需要修改的代码放进同一个类中。如果眼下没有合适的类安置这些代码,就创造一个。可以运用Inline Class把一系列相关行为放进同一个类。这可能造成Divergent Change,但你可以轻易处理它。

3.7.依恋情节(Feature Envy) 对其他类的兴趣高过自己所处类的兴趣。这种孺慕之情最通常的焦点便是数据。此时应该使用Move Method把这个函数移至另一个地点。

有时候函数中只有一部分受这种依恋之苦,此时应使用 Extract Method将这一部分提炼到独立函数中,再使用MoveMethod带它去梦想家园.

一个函数用到几个类的功能,那么Extract Method的Method究竟该置于何处呢?原则是:判断哪个类拥有最多被此函数使用的数据,然后就把这个函数和那些数据摆在一起。如果先以Extract Method将这个函数分解为数个较小函数并分别置放于不同地点,上述步骤也就比较容易完成了。

几个复杂精巧的模式破坏了这个规则。Strategy和Visitor。用这些模式对抗Divergent Change。最根本的原则是:将总是一起变化的东西放在一块。数据和引用这些数据的行为总是一起变化的,但也有例外。如果例外出现,我们就搬移哪些行为,保持变化只在一地发生。Stragegy和Visitor使你得以轻松修改函数行为,因为它们将少量被覆写的行为隔离开来,当然也付出了多一层间接层的代价。

3.8.数据泥团(Data Clumps)

数据项像小孩子,喜欢成群结队的待在一块。可以在很多地方常常看到相同的三四项数据:两个类中相同的字段,许多函数中相同的参数,这些总绑在一起出现的数据真应该拥有属于它们自己的对象。

首先找出这些数据项以字段形式出现的地方,运用Extract Class将它们提炼到一个独立对象中。

然后将注意力转移到函数签名上,运用Introduce Parameter Object或Preserve Whole Object为它减肥。这样可以是参数列缩短,简化函数调用。不必在意Data Clumps只用上新对象的一部分字段,只要以新对象取代两个(或更多)字段,你就值回票价了。

一个好的评判方法是:删掉众多数据项中的一项。这么做,其他数据有没有因而失去意义?如果它们不再有意义,这就是个明确信号:你应该为它们产生一个对象。

3.9.基本类型偏执(Primitive Obsession)

大多数编程环境的两种数据:

结构类型允许你将数据组织成有意义的形式,

基本类型则是构成结构类型的积木

结构总是带来额外的开销。它们可能代表着数据库中的表,如果只为做一两件事而创建结构类型可能显得太麻烦。

对象的一个极大的价值在于:它们模糊(甚至打破)了横亘于基本数据和体积较大的类之间的界限。你可以轻松编写出一些与语言内置(基本)类型无异的小型类。

3.10.switch惊悚现身(Switch Statements)

面向对象程序的一个最明显特征就是:少用switch(或case)语句。从本质上说,switch语句的问题在于重复。你常会发现同样的switch语句散布于不同地点。如果要为它添加一个新的case语句,要查找所有并一一修改。面向对象的多态概念可以为此带来更优雅的解决办法。

大多数时候,一看到switch语句,你就应该考虑以多态来替换它。问题是多态该出现在哪??????

switch语句常常根据类型码进行选择,你要的是与该类型码相关的函数和类,所以应该使用Extract Method将Switch语句提炼到一个独立函数中,再以MoveMethod将它搬至需要多态性的那个类里。此时你必须决定是否使用Replace Type Code with Subclasses或者Replace Type Code with State/Strategy。一旦完成这样的继承结构之后,就可以使用Replace Conditonal with Polymorphism.

如果只是在单一函数中有些选择事例,且并不想改动它们,那么多态就有点杀鸡用牛刀了。这种情况下 Replace Parameter with Explicit Methods是个不错的选择.

如果你的选择条件之一是nulll, 可以试试Introduce Null Object.

猜你喜欢

转载自blog.csdn.net/LightUpHeaven/article/details/84494325