2.遇到多个构造器参数时要考虑用构建器(Builder)

当一个类中的部分参数可选,部分参数必填的时候,我们会如何写这个类呢

使用构建器

  public class NutritionFacts {
    private final int servingSize;  // require
    private final int servings; //  require
    private final int calories; //  optional
    private final int fat;  // optional
    private final int sodium;   // optional
    private final int carbohydrate; //  optional

    public NutritionFacts(int servingSize, int servings) {
        this(servingSize,servings,0);
    }

    public NutritionFacts(int servingSize, int servings, int calories) {
        this(servingSize,servings,calories,0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, int fat) {
        this(servingSize,servings,calories,fat,0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
        this(servingSize,servings,calories,fat,sodium,0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) {
        this.servingSize = servingSize;
        this.servings = servings;
        this.calories = calories;
        this.fat = fat;
        this.sodium = sodium;
        this.carbohydrate = carbohydrate;
    }
}
   NutritionFacts cocaCola = new NutritionFacts(240,8,100,0,35,27);

构造器调用会使用很多我们根本不会用到的参数,但是还是不得不用,这里时全部设置成了0,仅仅是这6个参数看起来还不算太惨,但是参数越多,意味着构造器越多,这个类逐渐变的臃肿不堪

重叠构造器模式可行,但是有许多参数的时候,客户端代码很难编写,并且仍然较难以阅读

javaBean模式

public class NutritionFacts {
    private int servingSize = -1;  // require
    private int servings = -1; //  require
    private int calories = 0; //  optional
    private int fat = 0;  // optional
    private int sodium = 0;   // optional
    private int carbohydrate = 0; //  optional

    public NutritionFacts() {
    }

    public int getServingSize() {
        return servingSize;
    }

    public void setServingSize(int servingSize) {
        this.servingSize = servingSize;
    }

    public int getServings() {
        return servings;
    }

    public void setServings(int servings) {
        this.servings = servings;
    }

    public int getCalories() {
        return calories;
    }

    public void setCalories(int calories) {
        this.calories = calories;
    }

    public int getFat() {
        return fat;
    }

    public void setFat(int fat) {
        this.fat = fat;
    }

    public int getSodium() {
        return sodium;
    }

    public void setSodium(int sodium) {
        this.sodium = sodium;
    }

    public int getCarbohydrate() {
        return carbohydrate;
    }

    public void setCarbohydrate(int carbohydrate) {
        this.carbohydrate = carbohydrate;
    }
}

    NutritionFacts cocaCola = new NutritionFacts();
    cocaCola.setServingSize(240);
    cocaCola.setServings(8);
    cocaCola.setCalories(100);
    cocaCola.setSodium(35);
    cocaCola.setCarbohydrate(27);

使用javaBean创建实例很容易,代码阅读起来也很容易

但是缺点也十分明显,在类参数设置之前该类已经可以使用了,也就说如果你少了某个参数的话并不会影响什么,但是确实影响到了业务逻辑了,这在多线程上更加明显.说简单点的话,就是如果你少了某项参数没设置(或者你忘了),那依然能执行下去,但是结果可想而知

第二个缺点是,如果对象中含有final修饰的变量,那么是不能set的

builder模式

package com.chapter2;

public class NutritionFacts {
    private final int servingSize;  // require
    private final int servings; //  require
    private final int calories; //  optional
    private final int fat;  // optional
    private final int sodium;   // optional
    private final int carbohydrate; //  optional

    public 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 static class Builder {
        private int servingSize;  // require
        private int servings; //  require
        private int calories = 0; //  optional
        private int fat = 0;  // optional
        private int sodium = 0;   // optional
        private int carbohydrate = 0; //  optional

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder calories(int calories) {
            this.calories = calories;
            return this;
        }

        public Builder fat(int fat) {
            this.fat = fat;
            return this;
        }

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

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }
}
   NutritionFacts cocaCola = new Builder(240,8).sodium(10).build();

这样代码很容易编写,灵活并且又易于阅读,算是兼顾了以上的两种优点

我们可以使用泛型来创建builder抽象工厂

  public interface Builder {
    public T build();
}
public class NutritionFactsBuilder implements Builder {
    private int servingSize;  // require
    private int servings; //  require
    private int calories = 0; //  optional
    private int fat = 0;  // optional
    private int sodium = 0;   // optional
    private int carbohydrate = 0; //  optional

    public int getServingSize() {
        return servingSize;
    }

    public int getServings() {
        return servings;
    }

    public int getCalories() {
        return calories;
    }

    public int getFat() {
        return fat;
    }

    public int getSodium() {
        return sodium;
    }

    public int getCarbohydrate() {
        return carbohydrate;
    }

    public NutritionFactsBuilder(int servingSize, int servings) {
        this.servingSize = servingSize;
        this.servings = servings;
    }

    public Builder calories(int calories) {
        this.calories = calories;
        return this;
    }

    public Builder fat(int fat) {
        this.fat = fat;
        return this;
    }

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

    @Override
    public NutritionFacts build() {
        return new NutritionFacts(this);
    }
}

public class NutritionFacts {
    private final int servingSize;  // require
    private final int servings; //  require
    private final int calories; //  optional
    private final int fat;  // optional
    private final int sodium;   // optional
    private final int carbohydrate; //  optional

    public NutritionFacts(NutritionFactsBuilder builder) {
        this.servingSize = builder.getServingSize();
        this.servings = builder.getServings();
        this.calories = builder.getCalories();
        this.fat = builder.getFat();
        this.sodium = builder.getSodium();
        this.carbohydrate = builder.getCarbohydrate();
    }
}

builder的不足
builder的不足点是你想要得到目标对象的前提是你得先实例化builder对象,这回带来性能上的差异

我个人的理解: builder方法仅仅只能在工具类的地方使用,不然进行一些变种也是可以的,对于我现在来说 实体对象必不可少的有get和set方法.

总结

如果类的构造器或者静态工厂中具有对个参数,设计这种类的时,Builder模式就是种不错的选择.

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