java builder 模式(创建者设计模式)

359 阅读2分钟

当创建一个有多个参数对象时通常使用三种方式来创建

1.使用构造器创建

使用构造器时可能会针对不同参数创建多个构造器,发生构造器重载,使用起来不太方便,还要查看使用哪个构造器,并且多个参数也容易导致传参错误(参数顺序传错),生成错误的对象。对于必选参数和可选参数构造器的创建也要注意

2.使用JavaBean

JavaBean 模式就是使用 set(),方法对对象进行属性赋值,这种方式需要多次set,比较灵活,如果是必选参数就要通过一个构造器设置,并且不能使用空构造器。但是这种方式可以随时使用set()方法对对象的属性值进行修改,不能生成一个不可变对象。

3.使用builder模式(创建者设计模式)

该设计模式在对象内部使用一个Builder内部类,通过对builder对象的赋值来对外层对象属性赋值,外层对象的构造器私有化,避免外部创建,并且没有set()方法,生成的属性值不可改变。还可以在builder设置属性值时对参数校验。

下面是代码,摘抄自 effective-java

/**
 * builder 模式创建对象
 * 产生的对象不可变
 */
public class NutritionFacts {

    // final 不允许更改
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;

    // 仅在构造器时初始化属性, 构造器私有, 只能内部创建对象
    private NutritionFacts(Builder builder){
        this.servingSize = builder.servingSize;
        this.servings = builder.servings;
        this.calories = builder.calories;
        this.fat = builder.fat;
        this.sodium = builder.sodium;
    }

    @Override
    public String toString() {
        return "NutritionFacts{" +
                "servingSize=" + servingSize +
                ", servings=" + servings +
                ", calories=" + calories +
                ", fat=" + fat +
                ", sodium=" + sodium +
                '}';
    }

    // 使用 build 内部类创建对象
    public static class Builder{
        // 必须有的属性
        private final int servingSize;
        private final int servings;
        // 选填的属性
        private int calories = 0;
        private int fat = 0;
        private int sodium = 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){
            // 参数检查
            if (val > 100) throw new IllegalArgumentException();
            fat = val;
            return this;
        }

        public Builder sodium(int val){
            sodium = val;
            return this;
        }

        // 创建对象
        public NutritionFacts build (){
            return new NutritionFacts(this);
        }
    }

    public static void main(String[] args) {
        NutritionFacts nf1 = new Builder(3, 5).build();
        System.out.println(nf1);
        NutritionFacts nf2 = new Builder(3, 5).calories(12).fat(99).build();
        System.out.println(nf2);
    }

}