Effective Java-2. 当构造方法参数过多时使用builder模式

背景

静态工厂和构造方法不能很好的拓展到很多可选参数的场景,因为参数过多的时候,调用其构造方法不太能知道每个位置参数的含义,容易出bug

那么为这个类编写什么样下的构造方法或静态工厂呢?

  • 可伸缩构造方法模式
    • 例子:
    • 这个构造方法的调用需要许多你不想设置的参数,但是你不得不为它们传递一个值。 在这种情况下,我们为属性传递了 0 值。随着参数的增加容易失控
    • 难以读懂
// Telescoping constructor pattern - does not scale well!
class NutritionFacts {
    private final int servingSize; // (mL) required
    private final int servings; // (per container) required
    private final int calories; // (per serving) optional
    private final int fat; // (g/serving) optional
    private final int sodium; // (mg/serving) optional
    private final int carbohydrate; // (g/serving) 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;
    }
}
  • JavaBeans模式
    • 使用无参构造方法创建对象,调用setter方法设置成员属性
    • 构造对象过程被setter方法多次分割,可能处于不一致状态
    • 排除了让类不可变的的可能性
// JavaBeans Pattern - allows inconsistency, mandates mutability
public class NutritionFacts {
// Parameters initialized to default values (if any)
	private int servingSize = -1; // Required; no default value
	private int servings = -1; // Required; no default value
	private int calories = 0;
	private int fat = 0;
	private int sodium = 0;
	private int carbohydrate = 0;
	public NutritionFacts() { }
	// Setters
	public void setServingSize(int val) { servingSize = val; }
	public void setServings(int val) { servings = val; }
	public void setCalories(int val) { calories = val; }
	public void setFat(int val) { fat = val; }
	public void setSodium(int val) { sodium = val; }
	public void setCarbohydrate(int val) { carbohydrate = val; }
}

// ==================调用形式===================
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);

Builder模式

  • 可以生成流畅的API,易于阅读
  • builder 可以有多个可变参数,因为每个参数都是在它自己的方法中指定的,可以将传递给多个调用的参数聚合到单个属性中
  • 单个 builder 可以重复使用来构建多个对象,builder 的参数可以在构建方法的调用之间
    进行调整,以改变创建的对象,可以在创建时自动添加一些属性(例如递增的序列号)

具体用法参考建造者模式!!!

缺点:

  • 为了创建对象,必须创建一个Builder对象,可能会影响性能
  • builder模式比神所构造方法模式冗长,因此builder模式适用有足够的参数(或者未来可能有)
posted @ 2022-12-13 14:20  WYia  阅读(58)  评论(0编辑  收藏  举报