静态工厂和构造器都有个共同的局限性,它们都不能很好的扩展到大量的可选参数。
解决方式1、重叠构造器模式虽然可行,但是当有许多参数的时候,客户端代码会变得很难写,因为你并不能准确的知道这个参数到底对应哪个实参,很有可能就会不小心颠倒顺序而发生错误,并且就算写对了,对于阅读者也是极不友好的,后期维护困难。
解决方式2、Javabeans模式,在这种模式下,先调用一个无参构造器来创建对象,再通过调用setter来设置必要参数和可选参数。这种方式,虽然弥补了创建实例和阅读困难的不足,但是javabeans模式本身有着很严重的缺点。在构造过程中Javabeans可能处于不一致的状态(构造过程被分到了很多个调用中),当使用不一致状态的对象时会发生意想不到的失败。所以这个解决方法也不太可行。
主角:使用构建器。他既能想重叠构造器一样的安全,也能像javabeans模式一样的简单易读。它是建造者模式(设计模式的一种)的一种。
优点1、Builder模式模拟了具名的可选参数,就像Python和Scala中的一样。
优点2、Builder也使用与类层次结构
实例:
package builder;
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder{
//必要参数
private final int servingSize;
private final int servings;
//可选参数,初始化默认值为0
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public Builder(int servingSize,int servings){
this.servingSize = servingSize;
this.servings = servings;
}
/**
* 将calories赋值,并返回Builder对象
* @param val
* @return
*/
public Builder calories(int val){
calories = val;
return this;
}
/**
* 将sodium赋值,并返回Builder对象
* @param val
* @return
*/
public Builder sodium(int val){
sodium = val;
return this;
}
/**
* 将fat赋值,并返回Builder对象
* @param val
* @return
*/
public Builder fat(int val){
fat = val;
return this;
}
/**
* 将carbohydrate赋值,并返回Builder对象
* @param val
* @return
*/
public Builder carbohydrate(int val){
carbohydrate = val;
return this;
}
public NutritionFacts build(){
//调用顶级类的构造方法
//将builder对象的值都赋值给顶级类的变量
return new NutritionFacts(this);
}
}
/**
* 外部类的构造函数
* 将内部类的值赋给自己的变量
* @param builder
*/
private NutritionFacts(Builder builder){
this.servingSize = builder.servingSize;
this.servings = builder.servings;
this.calories = builder.calories;
this.fat = builder.fat;
this.sodium = builder.sodium;
this.carbohydrate = builder.carbohydrate;
}
public String toString(){
return "servingSize = " + servingSize + "\n"
+ "servings = " + servings + "\n"
+ "calories = " + calories + "\n"
+ "fat = " + fat + "\n"
+ "sodium = " + sodium + "\n"
+ "carbohydrate = " + carbohydrate;
}
public static void main(String[] args){
//调用Builder构建器来构建实例
NutritionFacts ntc = new NutritionFacts
.Builder(110, 10)
.calories(12)
.fat(20)
.sodium(42)
.carbohydrate(23).build();
//输出刚刚构造的对象的变量值
System.out.println(ntc.toString());
}
}
运行结果,说明构造成功。
不足:为了创建一个对象,必须先创建他的构建器。这样会增加一定的代码量,也会增加一定的开销。所以构建器主要用于参数比较多,而且大多数的参数都是可选的时候。当参数比较少时,优先考虑静态工厂方法。