重构-改善既有的代码设计(三)

1. 在对象之间搬移特性

1.1 Move Method(搬移函数)

你的程序中,有个函数与其所驻类之外的另一个类进行更多交流,调用后者或者被后者调用。在该函数最常用的类中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数,或者将旧函数完全移除。
动机
如果一个类中有太多行为,或者如果一个类与另一个类有太多合作而形成高度耦合,就应该搬移函数。
做法
- 检查源类中被源函数所使用的一切特性(包括字段和函数),考虑他们是否也该被搬移。
- 检查源类的子类和超类,看看是否有该函数的其他声明。
- 在目标函数中声明这个函数。
- 将源函数的代码复制到目标函数中。调整后者,使其能在新家中正常运行。
- 编辑目标类。
- 决定如何从源函数正确引用目标对象。
- 修改源函数,使之成为一个纯委托函数。
- 编译,测试。
- 决定是否删除源函数,或将它当做一个委托函数保留下来。
- 如果要移除源函数,请将源类中对源函数的所有调用,替换为对目标函数的调用。
- 编译,测试。
范例:略。

1.2 Move Field(搬移字段)

你的程序中,有个字段与其所驻类之外的另一个类更多地用到。在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段。
动机
对于一个字段,在其所驻类之外的另一个类中有更多函数使用了它,它就会考虑搬移这个字段。
做法
- 如果字段的访问级是public,使用Encapsulate Pield将它封装起来。
- 编译,测试。
- 在目标函数中建立与源字段相同的字段,并同时建立相应的设值/取值函数。
- 编辑目标类。
- 决定如何在源对象中引用目标对象。
- 删除源字段。
- 将所有对源字段的引用替换为对某个目标函数的调用。
- 编译,测试。
范例:略。

1.3 Extract Class(提炼类)

某个类做了应该由两个类做的事,建立一个新类,将相关的字段和函数从旧类搬移到新类。
动机
一个类应该只做一件事或者你发现子类变化只影响类的部分特性,或者你发现某些特性需要以一种方式来子类化,某些特性则需要以另一种方式子类化,这就意味着你需要分解原来的类。
做法
- 决定如何分解类所负的责任。
- 建立一个新类,用以变现从旧类中分离出来的责任 。
- 建立从旧类访问新类的连接关系。
- 对于你想搬移的每一个字段,运用Move Field搬移之。
- 每次搬移后,编译、测试。
- 使用Move Method将必要函数搬移到新类。先搬移较低层函数(被其他函数调用多于调用其他函数者),再搬移较高层函数。
- 每次搬移之后,编译,测试。
- 检查,精简每个类的接口。
- 决定是否公开新类。如果你的需要公开它,就要决定让他成为引用对象还是不可变的值对象。
范例:略。

1.4 Inline Class(将类内联化)

某个类没有做太多事情,将这个类的所有特性搬移到另一个类中,然后移除原类。
动机
如果一个类不再承担足够责任、不再有单独存在的理由,将这个类“塞进”另一个类中。
做法
- 在目标类身上声明源类的public协议,并将其中所有函数委托至源类。
- 修改所有源类引用点,该而引用目标类 。
- 编译、测试。
- 运用Move Method和Move Field,将源类的特性全部搬移到目标类。
- 为源类举行一个简单的“丧礼”。
范例:略。

1.5 Hide Delegate(隐藏“委托关系”)

客户通过一个委托类来调用另一个对象,在服务类上建立客户所需的所有函数,用以隐藏委托关系。
动机
用封装向客户隐藏委托关系,这样即使未来委托关系发生变化,变化也限制在服务对象,不会波及客户。
做法
- 对于每一委托关系中的函数,在服务对象端建立一个简单的委托函数。
- 调整客户,令它只调用服务对象提供的函数 。
- 每次调整后,编译并测试。
- 如果将来不再有任何客户需要取用Delegate,便可移除服务对象中的相关访问函数。
- 编译,测试。
范例:略。

1.6 Remove Middle Man(移除中间人)

某个类做了过多的简单委托动作,让客户直接调用受托类。
动机
中间委托人的动作过多,过于简单。
做法
- 建立一个函数,用以获得受托对象。
- 对于每个委托函数,在服务类中删除该函数,并让需要调用该函数的客户转为调用受托对象 。
- 处理每个委托函数后,编译、测试。
范例:略。

1.7 Introduce Foreign Method(引入外加函数)

你需要为提供服务的类增加一个函数,但你无法修改这个类,在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。
动机
你需要在服务类中添加一个函数,但你没有权限这么做。但是你发现自己为一个服务类建立了大量外加函数,或者发现有许多类都需要同样的外加函数,这时应该使用Introduce Local Extension。
做法
- 在客户类中建立一个函数,用来提供你所需要的功能。
- 以服务类实例作为该函数的第一个参数。
- 将该函数注释为:”外加函数(foreign method),应在服务类实现。“
范例:略。

1.8 Introduce Local Extension(引入本地扩展)

你需要为提供服务类提供一些额外函数,但你无法修改这个类,建立一个新类,使它包含这些额外函数。让这个扩张品成为源类的子类或包装类。
动机
你需要为提供服务类提供一些额外函数,但你无法修改这个类,这时你应该使用两种标准对象技术子类化subclassing和包装wrapping。这两种方法统称为本地扩展local extension。一般来说选中子类,这样的工作量比较少,但是如果制作子类对象的最大障碍在于,它必须在对象创建期实施。如果你想在对象创建之后再使用本地扩展,就有问题了。并且如果原数据允许修改,这时候就不能使用子类,因为一个修改不能同时改变两个副本,这时候必须使用包装类。
做法
- 建立一个扩展类,将它作为原始类的子类或者包装类。
- 在扩展类中加入转型构造函数。
- 在扩展类中加入新特性。
- 根据需要,将原对象替换为扩展对象。
- 将针对原始类定义的所有外加函数搬移到扩展类中。
范例:略。
本文引用自图灵程序设计丛书:重构 改善改善既有的代码设计。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值