第三章 代码的坏味道(二)

来源:互联网 发布:国大网络服装批发城 编辑:程序博客网 时间:2024/04/29 19:08

3.9 Primitive Obsession(基本型别偏执)
    不要固执地硬是要使用基本数据类型,要习惯于使用对象,即使对象里的东西很少。
3.10 Switch Statements(switch 惊悚现身)
   问题: 大多数时候,一看到switch语句及应该考虑[多态]来替换它。
   解决: 首先使用Extract Method(110)将switch语句提炼到一个独立函数中,再使用Move Method(142)将它搬移到需要多态性的那个class里头。此时你必须决定是否使用Replace Type Code with Subclasses(223)或Replace Type Code with State/Strategy.一旦完成继承结构之后,俺就可以运用Replace Conditional with Polymorphism(255)了。(适用于很懂地方都用到switch语句的时候哦)
    如果只是在单一函数中有些选择事例,用多态就有点杀鸡用牛刀了,这种情况下用Replace Parameter with Explicit Methods(285).

3.11 Parallel Inheritance Hierarchies(平行继承体系)
   问题:Parallel Inheritance Hierarchies是Shotgun Surgery的特殊情况。在这种情况下,每当你为某个class增加一个subclass,必须也为另一个class相应增加一个subclass.如果你发现某个继承体系的class名称前缀和另一个继承习题的class名称前缀完全相同,便是闻到了这种坏味道。
   解决:让一个继承体系的实体(instances)指向(参考、引用、refer to)另一个继承体系的实体(instances).如果再接再厉运用Move Method(142)和Move Field(146),及可以将指涉端(referring class)的继承体系消弭于无形。
3.12 Lazy Class(冗赘类)
   问题:项目中经常出现这样的情况:某个class原本对得起自己的身价,但重构使它身形缩水,不再做那么多工作;或开发者事前规划了某些变化,并添加一个class来应付这些变化,但变化实际没有发生。
   解决:如果某些subclass没有做满足够工作,事实Collapse Hierarchy(344).对几乎没用的组件,应该以Inline Class(154)对付它们。
3.13 Speculative Generality(夸夸其谈未来性)
   以“总有一天会做这个事情”为理由来走一些不必要的事情,结果往往造成系统更难理解和维护。
问题:
如果你的某个abstract class其实没有太大作用,请运用Collapse Hierarchy(344).非必要之delegation(委托)可运用Inline Class(154)除掉。
如果函数的某些参数未被用上,可对它事实Remove Parameter(277).
   如果函数名称带有多于的抽象意味,应该对它事实Rename Method(273)让它显示一些。
   如果函数或class的惟一用户是test cases(测试用例),这就飘出了坏味道Speculative Generality。如果你发现这样的函数或class,请把它们连同其test cases都删掉。但如果它们的用途是帮助test cases检测正当功能,当然必须刀下留人。
3.14 Temporary Field(令人迷惑的暂时值域)
   问题:某个instance变量仅为某种特定情势而设。这样的代码让人不易理解,因为你统称认为对象在所有时候都需要它的所有变量。在变量未被使用的情况下猜测当初设置目的,会让你发疯。
   解决:使用Extract Class(149)给这个可怜的孤儿创造一个家,然后把所有和这个变量相关的代码都放进这个新家。也许还可以使用Introdece Null Object(260)在【变量不合法】的情况下创建一个Null对象,从而避免写出【条件式代码】
   如果class中有一个复杂算法,需要好几个变量,往往就可能导致坏味道Temporary Field的出现。由于实现者不希望传递一长串参数,所以他把这些参数都放进值域中。都是这些值域只有在使用该算法时才有效,其它情况下会让人迷惑。这时候你可以利用Extract Class(149)把这些变量和其相关函数提炼到一个独立的class中,提炼后的新对象将是一个method object(其存在只是为了提供调用函数的途径,class本身并无抽象意味)。
3.15 Message Chains(过度耦合的消息链)
     问题:用户向一个对象索求另一个对象,然后再想后者索求另一个对象,然后再索求另一个对象....这就是Message Chain.
     解决:先观察MessageChain最终得到的对象是用来干什么的,看看能否以Extract Method(110)把使用该对象的代码提炼到一个独立函数中,再运用Move Method(142)把这个函数推入Message Chain.如果这条链上的某个对象有多位客户打算航行此航线的剩余部分,就加一个函数来做这件事。
     并不是任何函数链都是坏东西。
3.16 Middle Man(中间转手人)
     问题:某个class接口有一半的函数都委托给其它class。
     解决:使用Remove Middle Man(160),直接和实际对象打交道。如果这样【不干实事】的函数只有少数几个,可以运用Inline Method(117)把它们“inlining”,放进调用端。如果这些Middle Man还有其他行为,你可以运用Replace Delegation with Inheritance(355)把它变成实际对象的subclass,这样你既可以扩展原对象的行为,又不比负担那么多的委托动作。
3.17 Inappropriate Intimacy(亲呢关系)
    问题:如果两个类过于亲密,花费太多时间去探究彼此的private成分。
    解决:采用Move Method(142)和Move Field(146)帮他们划清界限。也可以看看是否运用Change Bidirectional Association to Unidirectional(200)(将双向关联改为单向)。如果两个classes是在是情投意合,可以运用Extract Class(149)把两者共同点提炼到一个安全地点,让它们坦荡地使用这个新class.或者可以尝试运用Hide Delegate(157)让另一个class来为它们传递信息。
     继承inheritance往往造成过度亲密,因为subclass对superclass的了解总是超过了superclass的主观愿望。如果你觉得该让这个孩子独自生活了,请运用Replace Inheritance with Delegation(352)让它离开继承。
3.18 Alternative Classes with Different Interfaces(异曲同工的类)
     如果两个函数做同一件事,却有不同的signature,请运用Rename Method(273)根据它们的用途重新命名。但这往往不够,请反复运用Move Method(142)将某些行为移入classes,直到两者的协议(protocols)一致为止。如果你必须重复而赘余地移入代码才能完成这些,或许可以运用Extract Superclass(336)为自己赎点罪。
3.19 Incomplete Library Class(不完美的程序库类)
     问题:Library Class并不是完美的。
     解决:如果只想修改library classes内的一两个函数,可以运用Introduce Foreign Method(162);如果想要添加一大堆额外行为,就得运用Introduce Local Extension(164).
3.20  Data Class(纯稚的数据类)
     所谓Data Class是指:它们拥有一些值域,以及用于访问(读写)这些值域的函数,除此之外一无长物。
    
3.21  Refused Bequest(被拒绝的遗赠)
      问题:subclasses应该继承superclass的函数和数据。但如果它们不想或不需要继承,该怎么处理呢?
      解决:
          传统的做法:为这个subclass新建一个兄弟(sibling class),在运用Push Down Method(328)和Push Down Field(329)把所有用不到的函数下推给那兄弟。这样一来superclass就只持有所有subclasses共享的东西。常常你会听到这样的建议:所有superclasses都应该是抽象的(abstract).
      不要胡乱修改继承体系,应该运用Replace Inheritance with Delegation(352)来达到目的。

3.22  Comments(过多的注释)
    如果你需要注释来解释一块代码做了什么,试试Extract Method(110);如果method已经提炼出来,但还是需要注释来解释其行为,试试Rename Method(273);如果你需要注释说明某些系统的需求规格,试试Introduce Assertion(267).
    当你感觉需要撰写注释,请先尝试重构,试着让所有注释都变得多余。
    如果你不知道该做什么,这才是注释的良好运用时机。除了用来记述将来的打算之外,注释还可以用来标记你并无十足把握的区域。你可以在注释里写下自己[为什么做某某事]。这些信息可以帮助将来的修改者。

 

原创粉丝点击