遇到多个构造器参数时要考虑用构建器

方法一是采用重叠构造器模式,缺点很明显,当参数很多时,需要的构造器要非常多,而且代码不易阅读。

方法二是采用JavaBeans模式,调用无参构造器来构造对象,再通过大量的set方法来设置参数,解决了方法一的缺点,但是构造过程被分到几个调用中,构造过程中JavaBean可能处于不一致的状态,需要额外的努力来确保它的线程安全(解决方法:当对象的构造完成,不允许在解冻之前使用,通过手动“冻结”对象,但是比较笨拙)。

方法三是采用Builder模式的一种形式,保证了安全性和可读性。
示例如下:

public class NutritionFacts {

    private Integer servingSize;
    private Integer servings;
    private Integer calories;
    private Integer fat;
    private Integer sodium;
    private Integer carbohydrate;
    
    public static class Builder {

        // Required parameters
        private Integer servingSize;
        private Integer servings;
        
        // Optional parameters
        private Integer calories;
        private Integer fat = 0; // 添加一个默认值
        private Integer carbohydrate;
        private Integer sodium;
        
        public Builder(Integer servingSize, Integer servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }
        
        public Builder calories(Integer calories) {
            this.calories = calories;
            return this;
        }
        
        public Builder fat(Integer fat) {
            this.fat = fat;
            return this;
        }
        
        public Builder carbohydrate(Integer carbohydrate) {
            this.carbohydrate = carbohydrate;
            return this;
        }
        
        public Builder sodium(Integer sodium) {
            this.sodium = sodium;
            return this;
        }
        
        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
        
    }
    
    private NutritionFacts(Builder builder) {
        this.servingSize = builder.servingSize;
        this.servings = builder.servings;
        this.calories = builder.calories;
        this.fat = builder.fat;
        this.carbohydrate = builder.carbohydrate;
        this.sodium = builder.sodium;
    }

    @Override
    public String toString() {
        return "NutritionFacts [servingSize=" + servingSize 
                + ", servings=" + servings + ", calories=" + calories
                + ", fat=" + fat + ", sodium=" + sodium 
                + ", carbohydrate=" + carbohydrate + "]";
    }
    
}
public class Test {

    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                                                    .calories(100)
                                                    .sodium(35)
                                                    .carbohydrate(27)
                                                    .build();
        System.out.println("cocaCola: " + cocaCola);
        NutritionFacts pepsiCola = new NutritionFacts.Builder(240, 8)
                                                     .calories(100)
                                                     .fat(35)
                                                     .carbohydrate(27)
                                                     .build();
        System.out.println("pepsiCola: " + pepsiCola);
    }

}
----------------------------------------------------  
输出:
cocaCola: NutritionFacts [servingSize=240, servings=8, calories=100, fat=0, sodium=35, carbohydrate=27]
pepsiCola: NutritionFacts [servingSize=240, servings=8, calories=100, fat=35, sodium=null, carbohydrate=27]

如果使用JDK1.5及以上版本,只要一个泛型就能满足所有的builder,无论它们在构建哪种类型的对象。

// A builder for objects of type T
public interface Builder {

    T build();
    
}
public class NutritionFacts {

    private Integer servingSize;
    private Integer servings;
    private Integer calories;
    private Integer fat;
    private Integer sodium;
    private Integer carbohydrate;
    
    public static class Builder implements com.sun.istack.internal.Builder {

        // Required parameters
        private Integer servingSize;
        private Integer servings;
        
        // Optional parameters
        private Integer calories;
        private Integer fat = 0; // 添加一个默认值
        private Integer carbohydrate;
        private Integer sodium;
        
        public Builder(Integer servingSize, Integer servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }
        
        public Builder calories(Integer calories) {
            this.calories = calories;
            return this;
        }
        
        public Builder fat(Integer fat) {
            this.fat = fat;
            return this;
        }
        
        public Builder carbohydrate(Integer carbohydrate) {
            this.carbohydrate = carbohydrate;
            return this;
        }
        
        public Builder sodium(Integer sodium) {
            this.sodium = sodium;
            return this;
        }

        @Override
        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
        
    }
    
    private NutritionFacts(Builder builder) {
        this.servingSize = builder.servingSize;
        this.servings = builder.servings;
        this.calories = builder.calories;
        this.fat = builder.fat;
        this.carbohydrate = builder.carbohydrate;
        this.sodium = builder.sodium;
    }

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

Builder模式也有不足,为了创建对象,必须先创建它的构建器,在某些十分注重性能的情况下,可能开销就有问题。Builder模式比重叠构造器模式更冗长。

你可能感兴趣的:(遇到多个构造器参数时要考虑用构建器)