重构(三)

9.Primitive Obsession(基本性别偏执)

Java以基本型别表示数值,以class表示字符串和日期------这两种型在其他语言中都是基本型别表示。作者说:面向技术的新手通常不愿意在小任务上运用小对象。像是结合数值和币别的moneyclass,含一个起始值和一个结束值的rangeclass,对于这些都可以运用Replace Data Vlue with Object(175,以对象取代数据值),进入炙手可热的对象世界。

比如说一个电话号码,通常在我们的设计里面它仅仅是一个字符串,但是后来发现又有了一些如[格式化],[抽取区号]的行为,在没有见到这则准则之前,我们通常是在哪个类里面用到电话号码就把这些方法放在哪里。但是这往往会引起Duplicate Code和Feature Envy,使用这个准则确实可以减去不少坏味道。

有时候这些数值是型别码,在C语言为基础的编程语言中,型别码是很常见的,但是在java中对于型别码有更好的处理方式。

对于那些不影响行为的型别码,也就是说不同的型别码并不需要不同的处理,不影响其他的一些行为,那么可以运用Replace Type Code with Class(128,以类取代型别码)。这里作者提到了一个很恰当的例子,就是血型,只有O,A,B,AB四种血型,这时可以使用一个BloodGroup血型类。

如果你有方法或者属性依赖于你的性别吗,那么使用Replace Type Code with SubClass(223,以子类型取代性别码)将会使很好的,借助多态来处理变化的行为,最大的好处在于:对不同行为的了解在class用户那儿转移到了class自身,当需要加入新的变化时,只需要加入一个subclass就行了。如果没有多态机制,我们就必须找到所有条件式。

在提到上面的重构准则的时候,作者都提到了一个一个方法就是Self Encapsulate Field(自封装值域),就是为值域设立set/get方法,好处就在于subclass可以通过[覆写一个函数]而改变获取数据的途径。

如果有一组总是被放在一起的值域,应该使用extract class,如果正在从array中挑选数据,可以运用Replace Array with Object(186,以对象取代数组)。比如,有时候我们并不是仅仅需要一个true/false的返回值而已,如果是false,我们可能还要得到false的原因(有多种),那么这时候你可能会想到以一个数组作为返回值,【0】代表true/fasle,【1】代表返回的具体信息。这确实是一种解决问题的方法,但是可读性确实是非常的差,这时我们可以建立一个专门的工具类,用来表示这种返回值。

10.  Switch Statements(switch惊悚现身)

(通常我用的是if else)作者提到:面向对象程序的一个最明显的特性就是:少用switch(或case)语句。大多数情况下,一看到switch语句就应该考虑[多态]来替换它。

首先可以使用Extract Method将swutch语句提炼到一个函数中,再用move Method将他们搬移到需要多台机制的class里,此时在决定是否使用Replace Type Code with SubClass,一旦完成这样的继承结构之后,我们就可以运用Replace Conditional with Polymorphism(255,利用多态取代条件式)。这里面的东西有点复杂,我只能照抄了。

11.Parallel Inheritance Hierarchies(平行继承体系)

这其实是Shotgun Surgery的特殊情况。在这种情况下,每当你为某个class增加一个subclass,必须也为另一个class相应增加一个subclass。消除这种重复性的一般策略是:让一个继承体系的实体(instances)指涉另一个继承体系的实体。如果再接再厉运用Move Method(142)和Move Field(146),就可以将指涉端的继承体系取出。(不是很明白,照抄)

12.Lazy Class

项目中的某个class原本有一定的价值,但是重构使得它身形缩水,不再做那么多工作。总之,因为各种原因,这个Class已经没有存在的必要,那么应该果断的取出他。

如果某个subclass没有做没有做满足够的工作,可以使用Collapse Hierarchy(344,折叠继承体系),将subclass和superclass何为一体。这里主要用到的方法是pull up Field、pull up Method、push Down method、push down field,把想要溢出的class内的所有行为搬移到另一个class。对于几乎没用的组件,应该使用Inline class(154,将类内联化)

13.Speculative Generality(夸夸其谈未来性)

做过多的预先设计,通常会照成系统的难理解和维护。没必要的委托可以用Inline class(154,将类内联化)去除掉。如果函数的某些参数未被用上,可对他实施Remove Parameter(277,移除参数)

14.Temporary Field(令人迷惑的暂时值域)

对于某些特定情势而设置的变量,通常会让人不理解,这时候可以用extract class为这个实例变量找一个住所,然后把所有和这个变量相关的代码都放进这个新家.对于一些[条件式代码],还可以使用Introduce Null Object(260,引入Null对象)在[变量不合法]的情况下创建一个Null对象。

15.Message Chains(过度耦合的消息链)

可能有些用户从一个对象索求另一个对象,然后再向后者索求另一个对象,然后再索求另一个对象,这就是Message Chains。对于这种过度紧密的耦合,你应该使用Hide Delegate(157,隐藏委托关系)也就是在server端放置一个简单的委托函数(delegate method),将委托关系隐藏起来,变化将被限制在server端中,不会设计客户端。

16.Middle Man(中间转手人)

对象的基本特性之一就是封装,对外部隐藏其北部细节,封装往往伴随着委托,但是过度运用delegation,可能会发现某个class接口有一般的函数都委托给其他的class,这就是过度运用delegation。这时候应该使用Remove Middle Man(160,移除中间人),有时候也可以运用Replace Delegation with Inheritance(355,以继承取代委托),对于这条准则,如果没有使用受托函数的所有函数(不是部分函数),那么就不该使用这个方法。

17.Inappropriate Intimacy(狎昵关系)

有时候你会看到两个class过于亲密,花费太多的时间去探究彼此的private成分。过分狎昵的classes必须拆散,可以使用move method 和move field帮他们划清界限。有时候也可以运用Change Bidirectional Association to Unidirectional(200,将双向关联改为单向关联)

继承往往照成过度的亲密,因为subclass对super class的了解总是超过superclass的主观愿望。这时候你可以使用Replace Inheritance with Delegation(352,以委托取代继承关系)

18. Alternative Classes with Different Interfaces(异曲同工的类)
  做相同事情的方法有不同的函数signature,一致把它们往类层次上移,直至协议一致。

19. Incomplete Library Class(不完善的程序类库)
  要建立一个好的类库非常困难。我们大量的程序工作都基于类库实现。然而,如此广泛而又相异的目标对库构建者提出了苛刻的要求。库构建者也不是万能的。有时候我们会发现库类无法实现我们需要的功能。而直接对库类的修改有非常困难。这时候就需要用各种手段进行Refactoring.

可以运用Introduce Foreign Method(162,引入外加函数)。当然如果一个server class建立了大量外加函数,就不应该使用本项重构,而应该使用Introduce Local Extension(164,引入本地扩张),建立一个新class,使它包含这些额外函数,让这个扩展成为Source class的subclass或wrapper(外覆类)。

20.Data Class(纯稚的数据类)

Data Class值:他们拥有一些值域(fields),以及用于访问(读写)这些值域的函数,除此之外没有其他东西。对于这些class,如果拥有public值域,请运用Encapsulate Field(206,封装值域),将他申明为private,并提供相应的访问函数。对于public类型的数据,其他对象有可能访问甚至修改这项数据,而拥有该数据的对象却毫无察觉。这就将数据和行为分开了。

如果这些classes内含容器类的值域,应该检查他们是否进行了恰当的封装。如果没有,就运用Encapsulate Collection(208,封装群集),让这个函数返回该群集的一个只读映件,宁在这个class中提供添加和删除群集元素的函数。

21. Refused Bequest
 超类传下来很多行为和状态,而子类只是用了其中的很小一部分。这通常意味着你的类层次有问题。

22. Comments

如果有一段代码有长长的注释,那么通常这个代码是糟糕的,Comments可以带我们找到各种坏味道。

如果你不知道该怎么做,这才是注释的良好时机。除了用来标记将来的打算之外,注释还可以用来标记你并无十足把握的区域。你可以在注释里写下自己[为什么做某某事]。这类信息可以帮助你将来的修改者,尤其是那些健忘的人。

<!--EndFragment-->

你可能感兴趣的:(数据结构,编程,工作,中间件,UP)