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

本文探讨了在处理大量可选参数时,静态工厂、构造器模式面临的扩展性问题,并引入了JavaBean模式与Builder模式作为替代方案,通过实例演示了如何更有效地构造复杂对象。

      静态工厂和构造器有个共同的局限性:它们都不能很好的扩展到大量的可选参数。

      例如:用一个类包装食品外面显示的营养成份标签。这些标签有几个域是必需的:每份的含量、每罐的含量以及每份的卡路里,还有超过20个可选域:总脂肪量、饱和脂肪量胆固醇、钠等等。

      对于这样的类,如果用重叠构造器模式,则需要创建许多拥有不同参数的构造器。下面举一个例子,这个食品有两个必选参数,四个可选参数。

public class NutritionFacts {
      private final int servingSize;                 //required
      private final int servings;                    //required
      private final int calories;                    //optional
      private final int fat;                         //optional
      private final int sodium;                      //optional
      private final int carbohudrate;                //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 carbohudrate){
       this.servingSize = servingSize;
       this.servings = servings;
       this.calories = calories;
       this.fat = fat;
       this.sodium = sodium;
       this.carbohudrate = carbohudrate;
      }
}
现在根据这个类创建一个实例:NutritionFacts cacaCola = new NutritionFacts(240,8,100,0,35,27);

这个构造器调用通常需要许多你本不想设置的参数,但还是不得不为它们传递值。随着参数数目增多,客户端代码会越发难写,越发难以阅读。

当有许多参数时,还有一种替代方法,即JavaBean模式。在这种模式下,调用一个无参构造器创建对象,然后调用setter方法设置每个必要的参数。

public class NutritionFacts {
      private int servingSize = -1;                 //required:no default value
      private int servings = -1;                    //required:no default value
      private int calories = 0;                    //optional
      private int fat = 0;                         //optional
      private int sodium = 0;                      //optional
      private int carbohudrate = 0;                //optional
     
     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 setCarbohudrate(int val){carbohudrate = val;}
}

创建实例:NutritionFacts cocaCola = new NutritionFacts();
                  cocaCola.setServingSize(240);
                  cocaCola.setServings(8);
                  cocaCola.setCalories(100);
                  cocaCola.setSodium(35);
                  cocaCola.setCarbohudrate(27);

 JavaBean模式也有很大的缺点,因为构造过程被分割成几个调用函数,在构造过程中JavaBean可能处于不一致状态。

最后介绍第三种方法,这就是Builder模式的一种形式。不直接生成想要的对象,然后客户端在builder对象上调用类似于setter的方法,

来设置每个相关的可选参数,最后调用无参的build方法生成不可变对象。

public class NutritionFacts {
      private NutritionFacts(Builder builder) {
       servingSize = builder.servingSize;
       servings = builder.servings;
       calories = builder.calories;
       fat = builder.fat;
       sodium = builder.sodium;
       carbohudrate = builder.carbohudrate;
 }

 private int servingSize;                 //required
      private int servings;                    //required
      private int calories;                    //optional
      private int fat;                         //optional
      private int sodium;                      //optional
      private int carbohudrate;                //optional
     
    public static class Builder{
      private final int servingSize;
      private final int servings;
      private int calories = 0;                   
         private int fat = 0;                        
         private int sodium = 0;                    
         private int carbohudrate = 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 carbohudrate(int val){
          carbohudrate = val;
          return this;
         }
        
         public NutritionFacts build(){
          return new NutritionFacts(this);
         }
    }
}

创建实例:NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohudrate(27).build();

 注意: Builder模式也有自己的不足,为创建对象,必须先创建它的构造器,在十分注重性能的情况下,要慎重使用。

             Builder模式比重叠构造器模式更加冗长,只有在很多参数时才使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值