一、Mvoe Method(搬移函数)
1、定义
有个函数与其所在类之外的另外一个类有更多交流,调用后者。在该函数最常引用的类中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数,或是将旧函数完全移除
2、动机
- 一个类与另外一个类有太多合作而形成高度耦合,就需要搬移函数
3、动机
- 检查源类中被源函数所使用的一切特性(包括字段和函数),考虑它们是否也该被搬移
- 检查源类的子类和超类,看看是否有该函数的其他声明。
- 在目标函数中声明这个函数
- 将源函数的代码复制到目标函数中
- 决定如何从源函数正确引用目标对象
- 决定是否删除源函数,或将它当作一个委托函数保留下来
- 如果要移除源函数,请将源类中对源函数的所有调用,替换为对目标函数的调用
二、Mvoe Field(搬移字段)
1、定义
有字段被其所在类之外的另外一个类更多地用到,在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段
2、动机
- 对于一个字段,在其所在类之外的另一个类中有更多的函数使用了它,则需要考虑搬移这个字段
3、做法
- 如果字段的访问级是public,使用Encapsulate Field(封装字段)将它封装起来
- 在目标类中建立与源字段相同的字段,并同时建立相应的设值、取值函数
- 决定如何在源对象中引用目标对象
- 删除源字段
- 将所有对源字段的引用替换为对某个目的函数的调用
三、Extract Class(提炼类)
1、定义
某个类做了应该由两个类做的事,建立一个新类,将相关的字段和函数从旧类搬移到新类
2、动机
- 一个类应该是一个清楚的抽象,处理一些明确的责任
- 有些类含有大量的函数和数据,这样的类往往太大而不易理解,此时需要考虑哪些部分可以分离出去,并将它们分离到一个单独的类中
- 如果子类化只影响类的部分特性,或某些特性需要以一种方式来子类化,某些特性则需要以另一种方式子类化,这就意味需要分解原来的类
3、做法
- 决定如何分解类所负的责任
- 建立一个新类,用以表现从旧类中分离出来的责任
- 建立从旧类访问新类的连接关系
- 运用Mvoe Field搬移每个需要搬移的字段
- 运用Move Method搬移必要的函数。先搬移较低层函数,再搬移高层函数
- 决定是否要公开新类
4、其他问题
- 是否公开新类,存在隐患:被修改。
- Extract Class是改善并发程序的一种常用技术,因为它可以为提炼后的两个类分别加锁,但是也存在危险,如果两个对象被同时锁定,就面临事物问题,需要使用其他类型的共享锁
四、Inline Class(将类内联化)
1、定义
某个类没有做太多事情,将这个类的所有特性搬移到另一个类中,然后移除原类。与Extract Class相反
2、动机
- 如果一个类不再承担足够责任,不再有单独存在的理由,需要将这个类移到另外一个类中
3、做法
- 在目标类身上声明源类的public协议,并将其中所有函数委托至源类
- 修改所有源类引用点,改而引用目标类
- 运用Move Method和Move Field,将源类的特性全部搬移到目录类
五、Hide Delegate(隐藏“委托关系”)
1、定义
客户通过一个委托类来调用另一个对象,在服务类上建立客户所需的所有函数,用以隐藏委托关系
2、动机
- 如果某个客户先通过服务对象的字段得到另一个对象,然后调用后者的函数,那么客户就必须知晓这一层委托关系。万一委托关系发生变化,客户也得相应变化。你可以在服务对象上放置一个简单的委托函数,将委托关系隐藏起来,从而去除这种依赖。这么依赖,即使将来发生委托关系的变化,变化也将被限制在服务对象中,不会涉及客户
3、做法
- 对于每个委托关系的函数,在服务对象端建立一个简单的委托函数
- 调整客户,令它只调用服务对象提供的函数
六、Remove Middle Man(移除中间人)
1、定义
某个类做了过多的简单委托动作,让客户直接调用受托类
2、动机
- 其实在Hide Delegate中,封装受托对象,是要付出代价的。每当客户要使用受托类的新特性时,就必须在服务端添加一个简单委托函数。随着受托类的特性越来越多,这一过程会让你痛苦不已。服务类就完全变成了一个中间人,此时应该让客户直接调用受托类
3、动机
- 建立一个函数,用以获得受托对象
- 对于每个受托对象,在服务类中删除该函数,并让需要调用该函数的客户转为调用受托对象
- 处理每个委托函数
七、Introduce Foreign Method(引入外加函数)
1、定义
如果需要为提供服务的类增加一个函数,但无法修改这个类。在客户类中建立一个函数,并以第一参数形式传入一个服务类实例
2、动机
- 在使用一个类,如果需要一项新服务,类无法提供
- 如果客户类多次使用这个函数,就得不断重复这些代码,应该将这些重复代码抽处理放进同一个函数中
3、做法
- 在客户类中建立一个函数,用来提供你需要的功能
- 以服务类实例作为该函数的第一个参数
八、Introduce Local Extension(引入本地扩展)
1、定义
需要为提供服务的类增加一个函数,但无法修改这个类。在客户类中建立一个函数,并以第一参数形式传入一个服务类实例
2、动机
- 如果需要的额外函数超过两个,外加函数就很难控制它们了,所以需要将这些函数组织在一起,放到一个恰当的地方。要达到这一目的,两种标准对象技术-子类化(subclassing)和包装(wrapping),统称为本地扩展
- 本地扩展:一个独立的类,但也是被扩展类的子类型,它提供源类的一切特性,同时额外添加新特性
3、做法
- 建立一个扩展类,将它作为原始类的子类或包装类
- 在扩展类中加入转型构造函数。转型构造函数是指接受原对象作为参数的操作函数
- 在扩展类中加入新特性
- 根据需要,将原对象替换为扩展对象
- 将针对原始类定义的所有外加函数版移到扩展类中