第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();//可以定义默认值

,可以直接构建
}