在Java编程中,静态工厂和构造函数都存在一个局限性:当可选参数数量较多时,它们的扩展性较差。以表示食品包装上营养成分标签的类为例,这些标签包含几个必需字段——如份量大小、每容器的份数和每份的卡路里——以及超过二十个可选字段,例如总脂肪、饱和脂肪、反式脂肪、胆固醇、钠等。大多数产品只有少数这些可选字段的值不为零。
在这种情况下,应该如何编写构造函数或静态工厂呢?传统上,程序员采用了“ telescoping constructor pattern”(逐层构造函数模式),这种模式提供了一个只接受必需参数的构造函数、一个接受一个可选参数的构造函数、一个接受两个可选参数的构造函数,依此类推,最终形成一个接受所有可选参数的构造函数。以下是这种模式的示例,为了简洁,仅显示了四个可选字段:
// 逐层构造函数模式 - 扩展性差! public class NutritionFacts { private final int servingSize; // (mL) 必需 private final int servings; // 必需 private final int calories; // 可选 private final int fat; // 可选 private final int sodium; // 可选 private final int carbohydrate; // (g/serving) 可选 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); } }
虽然这种方法在小范围内可行,但随着可选参数的增多,构造函数的数量迅速增加,导致代码难以管理和维护。
为了应对这一挑战,可以采用构建器模式。这种模式允许逐步构建对象,并在创建时提供灵活性和可读性。下面是使用构建器模式重构 NutritionFacts
类的示例:
public class NutritionFacts { private final int servingSize; // (mL) private final int servings; private final int calories; // 可选 private final int fat; // 可选 private final int sodium; // 可选 private final int carbohydrate; // 可选 private 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 final int servingSize; // (mL) private final int servings; private int calories = 0; // 默认值 private int fat = 0; // 默认值 private int sodium = 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 sodium(int val) { sodium = val; return this; } public Builder carbohydrate(int val) { carbohydrate = val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } }
使用构建器模式创建 NutritionFacts
实例变得简单且清晰:
NutritionFacts nutritionFacts = new NutritionFacts.Builder(240, 2) .calories(100) .fat(5) .sodium(10) .carbohydrate(20) .build();
这种方式不仅提高了可读性,还允许你在创建对象时轻松选择性地设置参数,从而避免了构造函数数量暴增的问题。构建器模式是处理多个构造参数的理想选择,特别是在面对许多可选字段时。
- EOF -