1 Chain Constructors
Chain the constructors together to obtain the least duplicate code when you have multiple constructors that contain duplicate code
现象:一个类中的多个构造函数含有相同的代码将会引起不必要的麻烦,当需要增加一个变量初始化时,有可能会漏掉一些构造函数
方法:Chain Constructors是Refactoring的一种方式,其目的是简减少重复代码。当多个构造函数含有相同的代码时,考虑Extract Method方法将相同的代码提取出来。
一般方法是:找出或构造一个Catch-All Constructor(包含所有构造信息)其它的构造函数调用该Catch-All构造函数
示例:
public Loan(float notional, float outstanding, int rating, Date expiry) {
this.strategy = new TermROC();
this.notional = notional;
this.outstanding = outstanding;
this.rating = rating;
this.expiry = expiry;
}
public Loan(float notional, float outstanding, int rating, Date expiry, Date maturity) {
this.strategy = new RevolvingTermROC();
this.notional = notional;
this.outstanding = outstanding;
this.rating = rating;
this.expiry = expiry;
this.maturity = maturity;
}
public Loan(CapitalStrategy strategy, float notional, float outstanding, int rating,Date expiry, Date maturity) {
this.strategy = strategy;
this.notional = notional;
this.outstanding = outstanding;
this.rating = rating;
this.expiry = expiry;
this.maturity = maturity;
}
在上面三个构造函数中,第三个函数包含了所有要初始化的信息,将其当作Catch-All Constructor,第一第二个函数改为:
public Loan(float notional, float outstanding, int rating, Date expiry) {
this(new TermROC(),notional,outstanding,rating,expiry,null);
}
public Loan(float notional, float outstanding, int rating, Date expiry, Date maturity) {
this(new TermROC(),notional,outstanding,rating,expiry,maturity);
}
2. Replace Multiple Constructors with Creation Methods
Too much constructors in a class make it hard to decide which constructor to call during development. You may use Replace the constructors with intention-revealing Creation Methods that return object instances.
过多的构造函数难于决定该调用哪一个,可以通过Creation Methods创建对象实例并返回该对象实例。
例如:
public class Loan {
private static String TERM_LOAN = "TL";
private static String REVOLVER = "RC";
private static String RCTL = "RCTL";
private String type;
private CapitalStrategy strategy;
private float notional;
private float outstanding;
private int customerRating;
private Date maturity;
private Date expiry;
public Loan(float notional, float outstanding, int customerRating, Date expiry) {
this(TERM_LOAN, new TermROC(), notional, outstanding,customerRating, expiry, null);
}
public Loan(float notional, float outstanding, int customerRating, Date expiry,Date maturity) {
this(RCTL, new RevolvingTermROC(), notional, outstanding, customerRating,expiry, maturity);
}
public Loan(CapitalStrategy strategy, float notional, float outstanding,
int customerRating, Date expiry, Date maturity) {
this(RCTL, strategy, notional, outstanding, customerRating,expiry, maturity);
}
public Loan(String type, CapitalStrategy strategy, float notional,
float outstanding, int customerRating, Date expiry) {
this(type, strategy, notional, outstanding, customerRating, expiry, null);
}
public Loan(String type, CapitalStrategy strategy, float notional,
float outstanding, int customerRating, Date expiry, Date maturity) {
this.type = type;
this.strategy = strategy;
this.notional = notional;
this.outstanding = outstanding;
this.customerRating = customerRating;
this.expiry = expiry;
if (RCTL.equals(type))
this.maturity = maturity;
}
}
以上的5个构造函数中,并没有重复的代码,5个相似的构造函数使得客户端不知道该如何去调用这些构造函数。通过重构用清晰而易于理解的Creation Methods来代替以上构造函数。
步骤:
1). 找出Catch-All Constructor, 将Catch-All Constructor设置为protected或private访问限制
2). For every type of object that can be created using one of the many constructors, create an
intention-revealing Creation Method.对每一个构造函数, 用一个清晰易于理解的Creation Method代替。
3). 将客户端使用构造函数创建对象的地方用Creation Method代替
示例类的构造函数可以创建以下的对象
a Term Loan with default capital strategy
a Term Loan with custom capital strategy
a Revolver with default capital strategy
a Revolver with custom capital strategy
an RCTL with default capital strategy
an RCTL with custom capital strategy
分别用Creation Method方法替代以上构造函数
重构的类代码如下:
public class Loan {
private static String TERM_LOAN = "TL";
private static String REVOLVER = "RC";
private static String RCTL = "RCTL";
private String type;
private CapitalStrategy strategy;
private float notional;
private float outstanding;
private int customerRating;
private Date maturity;
private Date expiry;
//Catch-All Constructor
protected Loan(String type, CapitalStrategy strategy, float notional,
float outstanding, int customerRating, Date expiry, Date maturity) {
this.type = type;
this.strategy = strategy;
this notional = notional;
this.outstanding = outstanding;
this.customerRating = customerRating;
this.expiry = expiry;
if (RCTL.equals(type)
this.maturity = maturity;
}
public static Loan newTermLoan(float notional, float outstanding, int customerRating,Date expiry) {
return new Loan(TERM_LOAN, new TermROC(), notional, outstanding, customerRating,expiry, null);
}
public static Loan newTermWithStrategy(CapitalStrategy strategy, float notional,
float outstanding, int customerRating, Date expiry) {
return new Loan(TERM_LOAN, strategy, new TermROC(), notional, outstanding,
customerRating, expiry, null);
}
public static Loan newRevolver(float notional, float outstanding, int customerRating,Date expiry) {
return new Loan(REVOLVER, new RevolverROC(), notional, outstanding,customerRating, expiry, null);
}
public static Loan newRevolverWithStrategy(CapitalStrategy strategy, float notional,
float outstanding, int customerRating, Date expiry) {
return new Loan(REVOLVER, strategy, new RevolverROC(), notional, outstanding,
customerRating, expiry, null);
}
public static Loan newRCTL(float notional, float outstanding, int customerRating,
Date expiry, Date maturity) {
return new Loan(RCTL, new RCTLROC(), notional, outstanding,customerRating, expiry, maturity);
}
public static Loan newRCTLWithStrategy(CapitalStrategy strategy, float notional,
float outstanding, int customerRating, Date expiry, Date maturity) {
return new Loan(RCTL, strategy, new RevolverROC(), notional, outstanding,
customerRating, expiry, maturity);
}
}
3 Encapsulate Subclasses with Creation Methods
适用性:Subclasses implement a common interface but are constructed in diverse ways
方法:Encapsulate the subclasses with intention-revealing Creation Methods in the base class
动机:隐藏子类实现
个人认为,该重构像Abstractor Factory Pattern. 通过Creation Method代替构造函数返回对象实例。有利于隐藏子类实现。
Abstract Factory通过Factory创建对象实例,而Encapsulate subclasses with Creation Methods将构造对象的函数置于基类中。
4 Extract Creation Class
适用性:Too many Creation Methods on a class obscure it's primary responsibility类中过多的Ceation Methods,不清楚其主要的责任。
方法:Move the Creation Methods for a related set of classes to one Creation Class将一系列相关类的Creation Method移到一个Creation Class中。
动机:该方法本质上来说是Extract Class. 一个类中含有大量的Creation Methods, 使人分不清该类的主要责任是什么。将这些Creation Method提取为一个类(类似于Abstract Factory).
备注:Creation Class与Abstract Factory不同点在于Creation Class创建对象是静态的,而Abstract Factory是运行时动态创建一系列对象。