「重构-在对象之间搬移特性」之解

在继上一章重构-重新组织函数之后,继续下一章的学习,来总结一下在对象之间搬移特性的几种常用重构手法。在对象之间搬移特性的最初动力来源于我们想把类以及对象这两类角色所应承担的责任和功能厘清,下面我们分别进行一一说明。

[1]Move Method(搬移函数)
解: 现在假设存在一个类A,A里面的某个方法aMethod常常使用类B中的某些特性(可能是值域,也可能是函数),这时我们就要思考了:也许把类A的这个方法移到类B中更合适。也许是当时规划做的不够,不过都没有关系,重构给了我们去重新审视和设计的机会,UML表示如下图所示:
move-method

[2]Move Field(搬移值域)
解: 搬移函数讨论的是在类之间转移函数的行为,而搬移值域相对来说讨论和关注的范围更细,类A里面的某个属性值aTemp在其所属的类之外更被经常使用,这样说起来很官方,说白了就是在其他类(比如类B)使用属性值aTemp的次数更频繁,这时我们是否可以考虑把这个属性移到类B中呢,修改用户对原类A中的aTemp引用,编译并测试,UML表示如下图所示:
move-field

[3]Extract Class(提炼类)
解: 这一手法更像是拆分,一个类里面杂糅了很多个方法和类变量(很可能是我们光顾着添加代码,增加功能来着),对于这个类,它应该承担的角色我们再也说不清,道不明,因为包含的功能太多了,好像具有这类功能,也具有其他类型的功能,这个时候就是Extract Class需要出场的时候了,把类里面所包含的函数按照功能进行归归类,然后把具有某种功能类型的函数提炼到新的类中,如果原类中剩下的函数所具备的功能已经不适合原类名(我们提倡见名知义),我们建议修改原类名,同时在原类中增加对新类的引用对象,原书中的UML图示例如下:
extract-class

[4]Inline Class(类内联化)
解: 所以说重构其实是一种方法论,我们总是会去探究重构的意义在哪里,让我们的代码清晰可读性强,扩展性强,让函数小而美。你看,这不又来了一个与Extract Class手法完全相反的手段Inline Class-将类进行内联化。我想正是重构手法(比如使用Extract Class手法)用的太多了,让某个类的功能变得特别简单,似乎都没有单独存在的必要了,这个时候我们就可以把这个类内联到使用这个类最频繁的用户类里面去了,UML示例刚好与上一手法相反。
inline-class

[5]Hide Delegate(隐藏委托关系)
解: 这一手法理解起来比较容易,从我们开始学习程序设计,就有一个概念一直贯穿始终,那就是-我们希望提供给用户的接口都是透明的。直白的说,最理想的情况是我们只告诉你这个接口的输入输出是什么,你并不需要去关心接口内部的实现逻辑,以及接口内部对其他类的调用关系,对于这些细节,我希望你知道的越少越好。隐藏委托关系,简单的说,其变化主要体现在:由原来的两类(client类直接调用target类中的函数)对象增加到三类对象(额外增加一类服务对象),client调用server对象,server对象真正去调用被代理对象(delegate,就是原先的target类),这样做的好处是隐藏delegate对象的实现细节,去除client对target对象的直接依赖,若target对象发生变化,该变化也只会影响server对象与delegate对象这一层关系上,client不会被影响到,UML示例如下:
hide-delegate

[6]Remove Middle Man(移除中间人)
解: 重构手法出神入化,你看又出现一对相反的手法,我们在享受Hide Delegate这一手法带来的好处的同时,细细想一下这一手法,也会发现有比较大的缺陷,表现在:以后凡是在被代理对象中新增特性时,我们都需要同时修改server对象,这未免显得有点繁琐且不必要,这个时候我们可以考虑对简单(「简单」这个程度我们怎么来定义:我的理解是不暴露被代理对象中的方法对其他类的调用关系)的代理关系采用Remove Middle Man手法进行移除,这个过程简单就不进行UML图示例了。

[7]Introduce Foreign Method(引入外部函数)
解: 这一手法产生的背景也很朴素简单易懂,举个例子:我们正在进行工程开发,架构师们封装了一套的jar包导入到我们当前的工程里面,这个时候我们发现jar包中的某个类(比如类A)缺了一个常用的方法,我们认为这个方法应该被包含进这个类中,可是我们没有权限去修改jar包的源代码,架构师们也忙,觉得当下没有必要进行改动,所以这个时候我们只能在自己的代码中加入这个方法,来补足原本类A应该提供的功能,不止我一个人这么干,小明也跟着这么干,重复就重复了,先不管了。这个时候我们完成的动作就是了引入了外部函数。

[8]Introduce Local Extension(进行局部扩展)
解: 我们在自己的代码里面针对类A补足的函数一个两个也就算了,结果发现越来越多了,超出两个了,这个时候如果还是把这些函数写在自己的代码中就会显得混乱,这个时候怎么办,有两种方法:我们去继承类A,或者写一个wrapper(外覆类)。外覆类的主要原理是:创建一个新类,在这个新类中存在对原类A对象的引用,同时补足我们认为类A缺失的方法;而继承类A指的是我们创建一个新类,同时extends类A,也补足我们认为类A缺失的功能,UML表示如下:
introduce-local-extension

重构的魅力在于变化,没有哪一种重构手法可以通吃天下,甚至手法与手法之间存在着矛盾,我们能做的是进行大量的实践,带着经验和方法论的指导去完成更好的代码实践。

本章完。

4 Comments

  1. WOW just what I wаs looking for. Came here ƅy searching for 几

    Reply
  2. Rebecca

    Hi my name is Rebecca and I just wanted to send you a quick message here instead of calling you. I came to your 「重构-在对象之间搬移特性」之解 – Triffic page and noticed you could have a lot more traffic. I have found that the key to running a popular website is making sure the visitors you are getting are interested in your website topic. There is a company that you can get keyword targeted visitors from and they let you try their service for free for 7 days. I managed to get over 300 targeted visitors to day to my site. http://labviewni.com/news/5j8

    Reply
  3. Pingback: 「重构-简化条件表达式」之解 – Triffic

  4. triffic (Post author)

    自己先占坑

    Reply

Leave a Comment

电子邮件地址不会被公开。 必填项已用*标注