学习重构(3)-在对象之间搬移特性

1. Move Method(搬移函数)

在该函数最常用的勒种简历一个有着类似行为的新函数,将就函数变成一个单纯的委托函数,或是将就函数完全移除。

应用场景:搬移函数是重构理论的支柱,如果一个类有太多行为,或者一个类与另一个类有太多合作而形成高度耦合,我们就需要搬移函数。通过这种手段,我们可以使系统中的类更简单,这些类最终也将更干净利落的实现系统交付的任务。

示例:

class A...

  void a1()...

  void a2() {

    B b = new B();

    b.b1();

    b.b2();

  }

class B...

  void b1()...

  void b2()...

重构为:

class A...

  void a2() {

    B b = new B();

    b.b3();

    b.b2();

    b.a1();

  }

class B...

  void b1()...

  void b2()...

  void a1()...

 

2. Move Field(搬移值域)

在目标类新建一个字段,修改元字段的所有用户,令他们改用新字段。

应用场景:在类之间移动状态和行为,是重构过程中必不可少的措施。随着系统发展,你会发现自己需要新的类,并需要将原本的工作职责拖到新的类中,当前合理而正确的设计决策,在未来可能不在正确,这没问题,如果你从来没遇到过这种情况,那才有问题。

示例:

class A...

  private int id;

  private String name;

class B...

  private String name;

重构为:

class A...

  private String name;

class B...

  private int id;

  private String name;

 

3.Extract Class(提炼类)

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

应用场景:你也许听过类似的教诲:一个类应该是一个清楚的抽象,处理一些明确的责任。但是实际工作中,类会不断成长扩张,你会在这加入一些功能,在那加入一些数据。给某个类添加一项新责任时,你会觉得不值得为这项新责任分离出一个单独的类。于是,随着责任不断增加,这个类变得过分复杂,成为一团乱麻。这样的类往往含有大量函数和数据,因为太大而不易理解。此时需要考虑将哪些部分可以分离出去,放到一个单独的类中。如果某些数据和某些方法总是一起出现,如果某些数据经常同时变化甚至彼此相依,这就表示它们应该被分离出去。

示例:

class Team...

  private String engineer1;

  private String engineer2;

  private String tester1;

  private String tester2;

重构为:

class Team...

  Engineer engineerTeam;

  Tester testerTeam;

class Engineer ...

  private String engineer1;

  private String engineer2;

class Tester...

  private String tester1;

  private String tester2;

 

4. Inline Class(将类内联化)

将这个类的所有特性搬移到另一个类种,然后移除原类。

应用场景:如果一个类不在承担足够的责任,不在有单独存在的理由(这通常是因为此前的重构动作移走了这个类的责任),此时就需要将这个萎缩类塞到其他的类中。

示例:

class Person...

  private String name;

  private Telephone telephone;

class Telephone...

  private String areaCode;

  private String number;

  String getTelephoneNumber()...

重构为:

class Person...

  private String name;

  private String areaCode;

  private String number;

  String getTelephoneNumber()...

 

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

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

应用场景:这个核心思想就是封装。如果某个客户调用了建立与服务对象某个值域基础之上的函数,那么客户就必须维护这层关系,一旦这层委托关系发生变化,比如此服务对象的值域有变化,那么客户也要去响应这个变化才能继续使用原来的函数。我们可以在服务端防止一个简单的委托函数,将这层委托关系隐藏起来,从而去除这个一寸性。这样即使将来委托关系发生变化,变化会被限定在服务端,客户不会受到影响。

示例:

class Client...

  void func1() {

    Person p = new Person();

    String manager = p.getDepartment().getManager();

class Person...

  Department getDepartment();

class Department...

  String getManager();

重构为:

  void func1() {

    Person p = new Person();

    String manager = p.getManager();

class Person...

  Department getDepartment();

  String getManager() {

    return getDepartment().getManager();

  }    

class Department...

  String getManager();

 

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

让客户直接调用委托类。

应用场景:与 第5条Hide Delegate(隐藏“委托关系”)正好相反,隐藏“委托关系”的代价是每当客户要使用受委托类的新特性时,就必须在服务端添加一个简单的委托函数,随着特性越来越多,带来的代价不断攀升。所以两种方法存在一个折中的关系,说不上绝对要使用哪一种,结合实际情况合理决策。

示例:

  void func1() {

    Person p = new Person();

    String manager = p.getManager();

class Person...

  Department getDepartment();

  String getManager() {

    return getDepartment().getManager();

  }    

class Department...

  String getManager();

重构为:

class Client...

  void func1() {

    Person p = new Person();

    String manager = p.getDepartment().getManager();

class Person...

  Department getDepartment();

class Department...

  String getManager();

 

7. Introduce Foreign Method(引入外加函数)

在client class中建立一个函数,兵役一个server class实体作为第一引数。

应用场景:当我们正在使用一个类,它为我们提供了想要的所有服务,突然有一天,我们需要一个新功能,但是这个类无法提供,如果可以修改源码,那么万事大吉,否则我们就只能在调用的地方去补齐我们的功能。如果只使用一次这个功能,那么额外编码工作没什么大不了,然后如果需要多次使用这个函数,就得不断重复这些代码。重复代码是软件万恶之源,这些重复代码应该被抽出来放进同一个函数中。进行本项重构时,如果以外加函数实现一项功能,那就是一个明确信号:这个函数原本应该在提供服务的类中加以实现。如果需要大量外加函数,那么这种方法就不建议使用了。外加函数终归是权宜之计,如果有可能,应该把这些函数放到他们的理想家园。

示例:

Date newStart = new Date(previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDate()+1);

重构为:

Date newStart = nextDay(previousEnd);

private static Date nextDay(Date date) {

  return new Date(date.getYear(), date.getMonth(), date.getDate()+1);

 

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

建立一个新class,使它包含这些额外函数。让这个扩展品成为source class的subclass(子类)或wrapper(外覆类)。

应用场景:类的作者无法预知未来,他们提供的函数可能不够用,如果我们可以修改源码,那么就可以很容易的增加或者修改已有类来满足使用;或者我们调用的地方少,增加的函数少时,可以使用第7条(Introduce Foreign Method(引入外加函数))来满足诉求。为了解决这个问题,我们需要将这些函数组织到一起,放到一个恰当的地方,此时,标准对象技术subclassing和wrapping是不错的选择。两种方法做选择时,首选subclass,这样的工作量比较少。

subclass或wrapper示例:

class SubDate extends Date {

  ....

class DateWrapper {

  private Date _date;

}

posted @ 2019-10-24 11:46  流浪的小丑  阅读(267)  评论(0编辑  收藏  举报