第2条--遇到多个构造器参数时考虑用构建器

这条其实没什么好说的,每个程序员都遇到过参数大爆炸的情况,面对大量的可选参数,怎么办?
直接上例子。考虑用一个类表示食品外包装的营养成分标签。这些标签中的有几个域是必须的:每份的分量,每罐的含量以及每份的卡路里,还有超过20个的可选域:总脂肪量,饱和脂肪量,转化脂肪,胆固醇等等,大多数产品在某几个域中都会有非零的值。

Public class NutritionFacts {
    private final int servingSize;//ml required
    private final int serings;// per container required
    private final int calories;//optional
    private final int fat;//g optional
    private final int sodium;//mg optional
    private final int carbonhydrate;//g optional
    public NutritionFacts(int servingSize,int serings){
        this(servingSize,servings,0);
    }
     
    public NutritionFacts(int servingSize,int serings,int calories){
        this(servingSize,serings,calories,0);
    }
     
    public NutritionFacts(int servingSize,int serings,int calories,fat){
        this(servingSize,serings,calories,fat,0);
    }
     
    public NutritionFacts(int servingSize,int serings,int calories,fat,sodium){
        this(servingSize,serings,calories,fat,sodium,0);
    }
     
    public NutritionFacts(int servingSize,int serings,int calories,fat,sodium,carbonhydrate){
        this.servingSize = servingSize;
        this.serings = servings;
        this.calories = calories;
        this.fat = fat;
        this.sodium = sodium;
        this.carbonhydrate = carbonhydrate;
    }
}

这种方式是最常见的,缺点也是显而易见的,代码的可读性非常差,而且非常容易出错。
另外一种常见的方式就是JavaBean的方式,先创建实例,再通过set方法初始化,这种方式的缺点也很明显,破坏了创建对象操作的原子性,在构造过程中对象可能处于不一致的状态。
好了,来看一个两全其美的办法吧:

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 carbonhydrate;
 
    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 carbonhydrate = 0;
         
        public Builder(int servingSize,int serving){
            this.servingSize = servingSize;
            this.servings = serving;
        }
         
        public Builder calories(int val){
            this.calories = val;
            return this;
        }
         
        public Builder fat(int val){
            this.fat = val;
            return this;
        }
         
        public Builder carbonhyate(int val){
            this.carbonhydrate = val;
            return this;
        }
         
        public Builder sodium(int val){
            this.sodium = val;
            return this;
        }
         
        public NutritionFacts build(){
            return new NutritionFacts(this);
        }
    }
     
    private NutritionFacts(Builder builder){
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbonhydrate = builder.carbonhydrate;
    }
     
    public static void main(String[] args) {
        NutritionFacts cocacola = new NutritionFacts.Builder(240,80).calories(100).sodium(35).carbonhyate(27).build();
    }
}

 怎么样,是不是两个缺点都避免了,安全性和可读性都很好,当然Builder模式也有它自身的不足,创建构建器会产生一定的开销,对性能要求非常严格的情况下就不一定是最完美的解决方案了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值