第2条:遇到多个构造器参数时要考虑用构建器
静态工厂和构造器有个共同的局限性,它们都不能很好地扩展到大量的可选参数。对于这样的类我们一般采用三种方式:
1.重叠构造器模式
在这种模式下,提供一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个构造器有两个可选参数,依次类推,直到最后一个构造
器包含所有的可选参数。
缺点:当有许多参数时,客户端代码会很难编写,并且难以阅读,代码不够优雅。
2.JavaBean模式
通过一个无参构造器创建对象,然后调用setter方法来设置每个必要的参数。这样创建实例很容易,产生的代码读起来也比较容易,也是开发软件上业务POJO常用的方式。
缺点:构造过程被分到了几个调用之中,在构造过程中无法保证JavaBean的一致性。所以适用性不够强大,多线程情况下安全隐患严重。
3.Builder模式
不直接生成想要的对象,而是让客户利用所有必要的参数调用构造器,得到一个builder对象,然后客户端在builder对象上调用类似于setter的方法设置每个可选参数,最后,客户端调用无参的build方法来生成不可变的对象。
与重叠构造器相比,builder牧师的客户端更易与阅读和编写;与JavaBeans相比,更加的安全
样例:
/**
* 建造者(Builder)模式 减少多构造参数的
*/
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int soduim;
private final int carbohydrate;
/**
* 内部类构建器 提供外部类返回值方法 参数为自己本身
*/
public static class Builder {
private final int servingSize;
private final int servings;
private int calories = 0;
private int fat = 0;
private int soduim = 0;
private int carbohydrate = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val){
calories = val;
return this;
}
public Builder fat(int val){
fat = val;
return this;
}
public Builder soduim(int val){
soduim = val;
return this;
}
public Builder carbohydrate(int val){
carbohydrate = val;
return this;
}
//可以加入验证用于增强功能
public NutritionFacts build(){
return new NutritionFacts(this);
}
}
/**
* 构造器为内部类参数,内部类拥有必要的默认值,如果不设置为默认值 设置则代替默认值。避免再次修改。提高安全性
* @param builder
*/
public NutritionFacts(Builder builder) {
this.servingSize = builder.servingSize;
this.servings = builder.servings;
this.calories = builder.calories;
this.fat = builder.fat;
this.soduim = builder.soduim;
this.carbohydrate = builder.carbohydrate;
}
NutritionFacts nutritionFacts = new Builder(32,11).calories(123).carbohydrate(12).carbohydrate(34).fat(5).build();//可以定义默认值
,可以直接构建
}