04.重构-在对象之间搬移特性

1. 问题及方案

  • 职责不清晰:Move Field、Move Method;
  • 类承担过多职责:Extract Class;
  • 类职责过少:Inline Class;
  • 类之间关联:Hide Delegate、Remove Middle Man;
  • 不能访问类的源码,却又想添加职责:Introduce Foreign Method、Introduce Local Extension;

2. Move Method(搬移函数)

问题:类中,有个函数与另一类过多交互。
在该函数最常引用的类中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数,或是直接移除。

2.1 动机

  • 类中有太多行为职责;
  • 类之间太多合作导致高度耦合;

3. Move Field(搬移字段)

问题:类中,某个字段被另外一个类更多的使用。
在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段。

3.2 做法

  • Self Encapsulate Field:即对字段进行包装,提高 get、set 操作;

4. Extract Class(提炼类)

建立一个新类,将相关的字段和函数从旧类搬移到新类。

4.1 动机

  • 类的职责过多;
  • 类有部分特性需子类化;

5. Inline Class(类内联化)

将这个类的所有特性搬移到另一个类中,然后移除原类。此手法正好与 Extract Class 相反。

5.1 动机

一个类不再承担足够职责,不再有单独存在的里有。

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

在服务类上建立客户所需的所有函数,用以隐藏委托关系。

6.1 动机

“封装”意味着每个对象都应该尽可能少了解系统的其他部分。

7. Remove Middle Man(移除中间人)

问题:某个类做了过多的简单委托动作。
让客户直接调用委托类。

7.1 动机

  • 合适的隐藏程度;
  • 与 Hide Delegate 相反;

8. Introduce Foreign Method(引入外部函数)

问题:你需要为提供服务的类增加一个函数,但无法修改这个类。
在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。

8.1 动机

  • 同样功能防止重复代码。
  • 若许多类都需要同样的外加函数,则应提取出来,使用 Introduce Local Extension。
    ps:类似 C# 的扩展函数。
  • 坚持“函数与数据应该被统一封装”的原则。

9. Introduce Local Extension(引入本地扩展)

问题:你需要为提供服务的类增加一些函数,但无法修改这个类。
建立一个新类,使它包含这些额外函数。让这个扩展品成为原类的子类或包装类。
ps:C# 的扩展方法更简单易用,若编程语言不支持扩展方法,则使用子类或包装类形式。

9.1 注意事项

  • 优先级:扩展方法 > 子类 > 包装类;
  • 添加“转型构造函数”,即源类型作为参数的构造函数;
  • 子类问题:必须在对象创建期实施、必须创建子类对象(若旧对象一直使用,则有两个对象保存原数据,数据修改会有问题);
  • 包装类 Wrapper;

参考

  • 《重构-改善既有代码的设计》(第7章)
坚持原创技术分享,您的支持将鼓励我继续创作!