重构—改善既有代码的设计003:代码的坏味道(Bad smells in Code)

重构—改善既有代码的设计003:代码的坏味道(Bad smells in Code)

    一:重复的代码(Duplicated Code)
    二:过长函数(LONG METHOD)
    三:过大类(LARGE CLASS)
    四:过长参数列(LONG PARAMETER LIST)
    五:发散式变化(DIVERGENT CHANGE)
    六:散弹式修改(SHOTGUN SURGERY)
    七:依恋情结(FEATURE ENVY)
    八:数据泥团(DATA CLUMPS)
    九:基本型别偏执(PRIMITIVE OBSESSION)
    十:SWITCH STATEMENTS
    十一:平行集成体系(PARALLEL INHERITANCE HIERARCHIES)
    十二:冗赘类(LAZY CLASS)
    十三:夸夸其谈的未来型(SPECULATIVE GENERALITY)
    十四:令人迷惑的暂时值域(TEMPORARY FIELD)
    十五:过度耦合的消息链(MESSAGE CHAINS)
    十六:中间转手人(MIDDLE MAN)
    十七:不恰当的亲密关系(INAPPROPRIATE INTIMACY)
    十八:异曲同工的类(ALTERNATIVE CLASSES WITH DIFFERENT INTERFACES)
    十九:不完美的程序库类(INCOMPLETE LIBRARY CLASS)
    二十:纯稚的数据类(DATA CLASS)
    二一:被拒绝的遗赠(REFUSED BEQUEST)
    二二:过多的注释(COMMENTS)

一:重复的代码(Duplicated Code)
    如果在一个以上的地点看到相同的程序结构,那么当可肯定:设法将它们合而为一,程序会变得更好。
    1:同一个CLASS内两个函数含有相同表达式EXTRACT METHOD
        提炼重复的代码,然后让这两个地点都调用被提炼出来的那一段代码。
    2:两个互为兄弟的子类含有相同表达式EXTRACT METHOD + PULL UP METHOD
        对两个类都提炼重复代码,将提炼出来的代码放入超类中。
    3:如果两个毫不相关的类EXTRACT CLASS
        将重复代码提炼到一个独立的CLASS中,然后再另一个CLASS中使用这个新CLASS

二:过长函数(LONG METHOD)
    每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立的函数中,并以其用途命名。
    百分之九十九的场合,要把函数变小,只需要使用EXTRACT METHOD,找到函数中适合集中在一起的部分,将它们提炼出来形成一个新的函数。
    1:如果函数内有大量的参数和临时变量,它们会对你的函数提炼形成阻碍。
        如果使用EXTRACT METHOD方法,最终会把许多参数和临时变量当做参数,传递给被提炼出来的新函数,导致可读性几乎没有任何提升。
        可以用REPLACE TEMP WITH QUERY来消除这些暂时的元素
        INTRODUCE PARAMETER OBJECT 和 PRESERVE WHOLE OBJECT则可以将过长的参数列表变得简洁一些。
    2:如果这是仍有太多的临时变量和参数,则可以考虑REPLACE METHOD WITH METHOD OBJECT

三:过大类(LARGE CLASS)
    1:如果单一CLASS做太多的事情,其内往往就会出现太多INSTANCE变量。
        可以用EXTRACT METHOD将数个变量一起提炼致新CLASS中。提炼时应该选择CLASS内彼此相关的变量,将它们放在一起。
    2:一个CLASS内如果有太多代码,也是代码重复,混乱,死亡的绝佳滋生地点。

四:过长参数列(LONG PARAMETER LIST)
    太长的参数列难以理解,太多参数会造成前后不一致,不易使用,而且一旦你需要更多的数据,就不得不修改它。
    可以通过传递对象类解决
    REPLACE PAREMETER WITH METHOD + PRESERVE WHOLE OBJECT + INTRODUCE PARAMETER OBJECT

五:发散式变化(DIVERGENT CHANGE)
    我们希望软件容易被修改,即一旦需要修改,希望能够调到某一点,只在该处修改。
    即针对某一外界便所的所有相应修改,都只应该发生在单一CLASS中,而这个新CLASS内的所有内容都应该反映该外界的变化。
    所以应该找出因着某些特定原因而造成的所有变化,然后应用EXTRACT CLASS将它们提炼到另一个CLASS中。

六:散弹式修改(SHOTGUN SURGERY)
    1:如果遇到某种变化,你都必须在许多不同CLASS内作出许多小修改以相应之。
        使用MOVE METHOD + MOVE FIELD把所有需要修改的代码放进同一个CLASS,如果没有适合的CLASS安置,就创造一个。
    2:区别
        发散式变化:一个CLASS受多种变化的影响
        散弹式修改:一种变化引发多个CLASS相应修改

七:依恋情结(FEATURE ENVY)
    对象:将数据和加诸其上的操作行为包装在一起
    1:函数对某个CLASS的兴趣搞过对自己所处之HOST CLASS的兴趣,常见的是数据。
        常看到某个函数为了计算某值,从一个对象那儿调用了几乎半打的取值函数。
        使用MOVE MOTHOD + EXTRACT METHOD将其移到它该去的地方。
    2:当一个函数用数个CLASS特性时,该放置何处?
        判断哪个CLASS拥有最多被此函数调用的数据,然后就把这个函数和那些数据摆在一起。

八:数据泥团(DATA CLUMPS)
    1:很多数据喜欢成群结队的待在一起,常常可以在很多地方看到相同的三或四笔数据项。
        将这些一起出现的数据放在一起,提炼到一个独立对象中。
    2:评判办法:删除众多数据中的一笔,其他数据没有因而失去意义?如果他们不再有意义,则说明该为它们产生一个新对象了。

九:基本型别偏执(PRIMITIVE OBSESSION)
    应用REPLACE DATA VALUE WITH OBJECT将原本单独存在的数据值替换为对象,从而走出传统的洞窟,进入只收可热的对象世界。

十:SWITCH STATEMENTS
    SWITCH语句的问题在于重复,常常发现同样的SWITCH语句三步于不同的地点,如果要为它添加一个新CASE子句,则必须找到所有SWITCH语句并修改它们。
    SWITCH可以考虑使用多态解决。
    用EXTRACT METHOD将SWITCH提炼到一个独立的函数中,用MOVE METHOD将它搬移到需要多态的类中。
    再用REPLACE TYPE CODE WITH SUBCLASS或REPLACE TYPE CODE WITH STATE/STRATEGY。
    这样,一般完成集成结构之后,就可以运用REPLACE CONDITIONAL WITH POLYMORPHISM了。

    如果只是在单一函数中有些选择事例,而又不想改动它们,那就没必要用多态了,REPLACE PARAMETER WITH EXPLICIT METHODS是个不错的选择。

十一:平行集成体系(PARALLEL INHERITANCE HIERARCHIES)
    每当为某个CLASS增加一个子类SUBCLASS时,也必须为另一个类CLASS相应增加一个子类SUBCLASS。

十二:冗赘类(LAZY CLASS)
    即如果一个类的所得不值得其身份,它就应该消失
    1:当一个类重构后,自身缩水
    2:开发者事前规划某些变化,并添加一个CLASS来应付这些变化,但变化实际上并没有发生
    3:如果某些子类没有做足够的工作,用COLLAPSE HIERARCHY。

十三:夸夸其谈的未来型(SPECULATIVE GENERALITY)
    用不上的装置只会档你的路,应搬开
    1:如果没有抽象类ABSTRACT CLASS没有太大的作用,可以运用COLLAPSE HIERARCHY除掉
    2:如果函数的某些参数未被用上,可用REMOVE PARAMETER去除
    3:如果函数名称带有多于的抽象意味,可用RENAME METHOD去除
    4:如果函数或CLASS得惟一用户是测试用例,则去除

十四:令人迷惑的暂时值域(TEMPORARY FIELD)
    有些对象的某些变量仅为某种特定情势而设,这样的代码让人不易理解。因为通常认为对象在所有时候都需要它的所有变量。
   
十五:过度耦合的消息链(MESSAGE CHAINS)
    观察MESSAGE CHAIN最终得到的对象是用来干什么的,看看是否已EXTRACT METHOD把使用该对象的代码提炼到一个独立的函数中,再运用MOVE METHOD把这个函数推入MESSAGE CHAINS中。

十六:中间转手人(MIDDLE MAN)
    1:当某个CLASS接口有一半的函数都委托给其他CLASS时,就存在过度应用了。这时应该直接和实际对象打交道。
    2:如果这样不干实事的函数只有少数几个,可以运用INLINE METHOD把它们内联进调用端。

十七:不恰当的亲密关系(INAPPROPRIATE INTIMACY)
    过分亲密的类必须拆散。可以使用MOVE METHOD 和 MOVE FIELD帮它们划清界面,从而减少亲密行为。
    如果两个类是在情投意合,可以运用EXTRACT CLASS把两者共同点提炼到一个安全地点,让他们坦荡地使用这个新类。
   
十八:异曲同工的类(ALTERNATIVE CLASSES WITH DIFFERENT INTERFACES)
    如果两个函数做同一件事情去,却有着不同的签名,需应用RENAME METHOD根据他们的用途重新命名。

十九:不完美的程序库类(INCOMPLETE LIBRARY CLASS)
    库类的构建者没有未卜先知的能力。
    麻烦的是类库的形式往往不够好,往往不可能让我们修改其中的类使它完成我们希望的工作。
    如果想修改库类的一两个函数,可以应用INTRODUCE FOREIGN METHOD
    如果想要添加一大堆额外行为,就得应用INTRODUCE LOCAL EXTENSION

二十:纯稚的数据类(DATA CLASS)
    DATA CLASS:即拥有一些值域,以及用于访问这些值域的函数,除此之外一无长物。
    这些类早期可能还有PUBLIC值域或容器,这是应该用ENCAPSULATE FIELD将它们封装起来。对于那些不该被其他类修改的值域,应用REMOVE SETTING METHOD

二一:被拒绝的遗赠(REFUSED BEQUEST)
    子类应该继承父类的函数和数据,但如果它们不想或不需要继承,这时该如何?
    传统做法,为这个子类新建一个兄弟,在运用PUSH DOWN MOETHOD+PUSH DOWN FIELD把所有用不到的函数下推给那个兄弟。
    这样一来,父类就只持有所有子类共享的东西。

二二:过多的注释(COMMENTS)
    当感觉需要注释时,请先尝试重构,试着让所有注释都变得多余。
    有时看到一段长长的注释,而这些注释之所以存在是因为代码很糟糕。

 

 

 

 

 

 

你可能感兴趣的:(设计模式)