静态工厂和构造器有个共同的局限性:都不能很好地扩展大量的可选参数
例:
考虑用一个类表示包装食品外面显示的营养成分标签。这些标签中有几个域是必需的:每份含量,每罐含量,每份卡路里,还有超过20个可选域:总脂肪量,饱和脂肪量,转化脂肪量,胆固醇,钠等等。大多数的产品在某几个可选域中都会有非0的值。
对于这样的类,应该用哪种构造器或者静态方法来编写呢?
1. 重叠构造器 (telescoping constructor)
   提供第一个只有必要参数的构造器
   提供第二个包含必要参数且包含一个可选参数的构造器
   提供第三个包含必要参数且包含两个可选参数的构造器
   以此类推,最后一个构造器包含所有参数
   如下是个简单的示例
   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
   | public class NutritionFacts {     private final int servingSize;      private final int servings;      private final int calories;      private final int fat;           private final int sodium;        private final int carbohydrate; 
           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;     } }
  | 
 
仅仅想创建一个该类对象,使用最短的构造器即可
但如果想要设置参数表中靠后的参数问题就来了
1
   | NutritionFacts cocaCola = new NutritionFacts(240,8,100,0,35,27);
   | 
 
如上初始化中 fat 的值为0,这个参数本是不用初始化的,就6个参数的情况下,还说的过去,随着参数增加,这样就不行了。
重叠构造器是可行的,但当参数增多时,客户端的代码将变得很难编写,阅读性也较差,并且如果初始化时容易填错顺序,导致运行时的错误。
2. JavaBeans模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
   |  public class NutritionFacts {     private int servingSize = -1;      private int servings = -1;      private int calories = 0;      private int fat = 0;           private int sodium = 0;        private int carbohydrate = 0; 
      public NutritionFacts() {     }
      public void setServingSize(int servingSize) {         this.servingSize = servingSize;     }
      public void setServings(int servings) {         this.servings = servings;     }
      public void setCalories(int calories) {         this.calories = calories;     }
      public void setFat(int fat) {         this.fat = fat;     }
      public void setSodium(int sodium) {         this.sodium = sodium;     }
      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);
 
  | 
 
JavaBeans模式创建实例很容易,代码可读性也很强,但其有很严重的缺点:
构造的过程包含多个调用,在构造过程中JavaBeans可能处于不一致状态
例如一个线程正在使用setter初始化值,而另一个线程正用getter取得该对象的字段
 
使用JavaBeans模式则该类不可成为不可变类 (因为有setter访问器)
 
3. Builder模式
此模式有重叠构造器的安全性,也有JavaBeans模式的高可读性
不直接生成需要的对象,而是得到一个builder对象,调用所有的必要的构造器或静态工厂,设置每一个需要设置的参数,最后调用一个无参数的build方法来生成一个不可变对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
   | public class NutritionFacts {     private final int servingSize;     private final int servings;     private final int calories;     private final int fat;     private final int sodium;     private final int carbohydrate;
      public NutritionFacts(Builder builder) {         servingSize = builder.servingSize;         servings = builder.servings;         calories = builder.calories;         fat = builder.fat;         sodium = builder.sodium;         carbohydrate = builder.carbohydrate;     }
      public static class Builder {                  private int servingSize;         private int servings;         private int calories;         private int fat;         private int sodium;         private int carbohydrate;
          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 Builder carbohydrate(int carbohydrate) {             this.carbohydrate = carbohydrate;             return this;         }
          public NutritionFacts build() {             return new NutritionFacts(this);         }     } }
 
  NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();
  | 
 
Builder 模式的可读性提高了很多,代码简易。Builder模式模拟了了具名可选参数
如果该类包含多个字段,Builder模式就是种不错的选择,特别是当大多数参数都是可选的时候。与重叠构造器与JavaBeans相比要更加安全与易读。