反向重构:提炼类(182)

  class Person {
 get officeAreaCode() {return this._telephoneNumber.areaCode;}
 get officeNumber()  {return this._telephoneNumber.number;}
}
class TelephoneNumber {
 get areaCode() {return this._areaCode;}
 get number() {return this._number;}
}
 
 
  class Person {
 get officeAreaCode() {return this._officeAreaCode;}
 get officeNumber()  {return this._officeNumber;}

动机

内联类正好与提炼类(182)相反。如果一个类不再承担足够责任,不再有单独存在的理由(这通常是因为此前的重构动作移走了这个类的责任),我就会挑选这一“萎缩类”的最频繁用户(也是一个类),以本手法将“萎缩类”塞进另一个类中。

应用这个手法的另一个场景是,我手头有两个类,想重新安排它们肩负的职责,并让它们产生关联。这时我发现先用本手法将它们内联成一个类再用提炼类(182)去分离其职责会更加简单。这是重新组织代码时常用的做法:有时把相关元素一口气搬移到位更简单,但有时先用内联手法合并各自的上下文,再使用提炼手法再次分离它们会更合适。

做法

对于待内联类(源类)中的所有 public 函数,在目标类上创建一个对应的函数,新创建的所有函数应该直接委托至源类。

修改源类 public 方法的所有引用点,令它们调用目标类对应的委托方法。每次更改后运行测试。

将源类中的函数与数据全部搬移到目标类,每次修改之后进行测试,直到源类变成空壳为止。

删除源类,为它举行一个简单的“丧礼”

范例

下面这个类存储了一次物流运输(shipment)的若干跟踪信息(tracking information)。

class TrackingInformation {
  get shippingCompany() {
    return this._shippingCompany;
  }
  set shippingCompany(arg) {
    this._shippingCompany = arg;
  }
  get trackingNumber() {
    return this._trackingNumber;
  }
  set trackingNumber(arg) {
    this._trackingNumber = arg;
  }
  get display() {
    return `${this.shippingCompany}: ${this.trackingNumber}`;
  }
}

它作为 Shipment(物流)类的一部分被使用。

class Shipment…

get trackingInfo() {
 return this._trackingInformation.display;
}
get trackingInformation() {return this._trackingInformation;}
set trackingInformation(aTrackingInformation) {
 this._trackingInformation = aTrackingInformation;
}

TrackingInformation 类过去可能有很多光荣职责,但现在我觉得它已不再能肩负起它的责任,因此我希望将它内联到 Shipment 类里。

首先,我要寻找 TrackingInformation 类的方法有哪些调用点。

调用方…

aShipment.trackingInformation.shippingCompany = request.vendor;

我将开始将源类的类似函数全都搬移到 Shipment 里去,但我的做法与做搬移函数(198)时略微有些不同。这里,我先在 Shipment 类里创建一个委托方法,并调整客户端代码,使其调用这个委托方法。

class Shipment…

    set shippingCompany(arg) {this._trackingInformation.shippingCompany = arg;}

调用方…

aShipment.trackingInformation.shippingCompany = request.vendor;

对于 TrackingInformation 类中所有为客户端调用的方法,我将施以相同的手法。这之后,我就可以将源类中的所有东西都搬移到 Shipment 类中去。

我先对 display 方法应用内联函数(115)手法。

class Shipment…

get trackingInfo() {
  return `${this.shippingCompany}: ${this.trackingNumber}`;
}

再继续搬移“收货公司”(shipping company)字段。

get shippingCompany() {return this._trackingInformation._shippingCompany;}
set shippingCompany(arg) {this._trackingInformation._shippingCompany = arg;}

我并未遵循搬移字段(207)的全部步骤,因为此处我只是改由目标类 Shipment 来引用 shippingCompany,那些从源类搬移引用至目标类的步骤在此并不需要。

我会继续相同的手法,直到所有搬迁工作完成为止。那时,我就可以删除 TrackingInformation 类了。

class Shipment…

get trackingInfo() {
 return `${this.shippingCompany}: ${this.trackingNumber}`;
}
get shippingCompany()    {return this._shippingCompany;}
set shippingCompany(arg) {this._shippingCompany = arg;}
get trackingNumber()    {return this._trackingNumber;}
set trackingNumber(arg) {this._trackingNumber = arg;}