4. 在对象之间搬移特性

在对象的设计过程中,“ 决定把责任放在哪儿”即使不是最重要的事,也是最重要的事之一。常常只需要使用 Move method和move field简单地移动对象行为,就可以解决这些问题。如果这两个手法都需要用到,建议先使用move field再使用move method。

类往往会因为承担过多责任而变得臃肿不堪。这时可以使用Extract Class将一部分责任分离出去。如果一个类变得“不负责任”,就使用Inline Class将它融入另一个类。如果一个类使用了另一个类,运用Hide Delegate将这种关系隐藏起来通常是有帮助的。有时候隐藏委托类会导致拥有者的接口经常变化,此时需要使用Remove middle Man。

4.1 move method(搬移函数)
程序中,有个函数与其所驻类 之外的另一个类进行更多交流,调用后者或被后者调用。就在该函数最常引用的类中建立一个由类似行为的新函数,将旧函数变成一个单纯的委托函数,或是将旧函数完全移除。有时候搬移一组函数比逐个搬移更简单些。

就像图中aMethod()方法老是与Class2交互,那干脆让它们在一起好了。把功能放到Class2中,然后Class1只是直接或间接调用这个方法即可。

4.2 Move field (搬移字段)
程序中某个 字段被其所驻类 之外的另一个类更多地用到,就可以在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段。

在类之间移动状态和行为,是重构过程中必不可少的措施。上述所谓使用可能是通过getter/setter间接进行的。

4.3 Extract Class (提炼类)
程序中某个类做了应该由两个或更多类做的事,就应该建立一个或多个新类,将相关的字段和函数从旧类搬移到新类。

可以结合move field和move method来达到拆分的目的。 拆分原则就是单一职责,一个类只做一件事情。

4.4 Inline Class (将类内联化)
某个类没有做太多事情,就将这个类所有特性搬移到另一个类中,然后移除原类。

Inline Class正好与extract class相反需要判断要消除的类的语义是否跟要融入的类的语义接近。

4.5 Hide Delegate (隐藏委托关系)
客户通过一个委托类来调用另一个对象。在服务类上建立客户所需的所有函数,用以隐藏委托关系。


“封装”即使不是对象的最关键特征,也是最关键特征之一。“封装”意味着每个对象都应该尽可能少了解系统的其他部分。如此一来,一旦发生变化,需要了解这一变化的对象就会比较少,这会使变化比较容易进行。
如果某个客户先通过服务对象的字段得到另一个对象,然后调用后者的函数,那么客户就必须知晓这一层委托关系,万一委托关系发生变化,客户也得相应变化。

可以对比4.6的方法,恰当的把握两者的度真的不是那么容易,但我们要知晓,委托和直接调用之间有那么一个“合适的封装和简单的委托”关系。

4.6 Remove Middle Man(移除中间人)
某个类做了 过多的简单委托动作,那就让客户直接调用受委托类,移除中间人。


在讨论Hide Delegate时我们谈到了“封装受委托对象”的好处。但是这层封装也是要付出代价的,每当客户要使用受委托类的新特性时,就必须在服务端添加一个简单委托函数。随着受委托类的特性越来越多,这一过程会让你痛苦不已。 服务类完全变成了一个“中间人”,此时就应该让客户直接调用受托类。

很难说什么程度的隐藏才是合适的。还好,有了Hide Delegate和Remove Middle man,我们就可以在系统运行过程中不断进行调整。随着系统的变化,“合适的隐藏程度”这个尺度也相应改变。

4.7 Introduce foreign Method (引入外加函数)
当需要为提供服务的类增加一个函数,但无法修改这个类时(比如是第三方的类),我们可以在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。


4.8 Introduce Local extension (引入本地扩展)
当需要为服务类提供一些额外函数,但无法修改这个类,可以建立一个新类,使它包含这些额外函数,让这个扩展类称为源类的子类或包装类。


这与Introduce foreign method的区别就是需要扩展的方法比较多。 这也体现了使用组合来代替继承来达到扩展功能的设计思想。
如果只需要扩展一两个函数,就可以使用Introduce foreign method,但如果需要的额外函数超过两个,外加函数就很难控制了,所以就需要将这些函数组织在一起,放到一个恰当地方去。要达到这一目的,两种标准对象技术:子类化(subclassing)和包装(wrapping)是显而易见的办法,我们把这统称为本地扩展。

对比上一篇,如果在一个单独的类中使用extract method等方法已经不能做好内部优化了,那就需要在类之间来做交换或扩展了。

猜你喜欢

转载自zoroeye.iteye.com/blog/2197480