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

原因

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

现行解决方法

1.使用重叠构造器:

    public class NutritionFacts{
        private NutritionFacts(int servings){ ...//初始化}
        private NutritionFacts(int servings, int calories){ ...}
        private NutritionFacts(int servings, int calories, int fat){ ...}
    }

但是这样的构造器多了许多你不想要设置的参数,还不得不为它们传递值。

缺点:非必填参数比较多时,客户端代码会很难编写,并且难以阅读。而且如果客户端不小心颠倒了其中两个参数的顺序,编译器不会出错,但是程序运行时会出现错误。

2.使用JavaBean,调用一个无参构造器来创建对象,调用setter方法来设置每个必要的参数,以及可选参数:

      public class NutritionFacts {
        private int servings = -1;
        public NutritionFacts(){}
        public setServings(int val){ servings = val;}
    }

缺点:在构建过程中JavaBean可能处于不一致的状态(不一致的状态:我的理解是必填参数可能没有设置,导致调用过程中导致报错,如果有人理解这里说的不一致的状态可以和我讲解下)。另外JavaBean阻止了把类做成不可变的可能,需要付出额外的努力来确保它的线程安全(有兴趣的可以去了解下什么叫线程安全和非线程安全)。

3.使用构建器模式:不直接生成想要的对象,让客户端利用所有必要的参数调用构造器,得到一个builder对象;然后在builder对象上调用类似于setter的方法,来设置每个相关的可选参数;最后在客户端调用无参的build方法来生成不可变对象。

      public class NutritionFacts {
        private final int servings;
        private final int calories;
        private final int fat;
       
        public static class Builder {
            private int servings = 0;
                 private int calories = 0;
            private int fat = 0;
            //传入必填参数
            public Builder(int servings,int calories){
                this.servings = servings;
                this.calories = calories;
            }
            //非必填参数
            public Builder fat(int val){
                this.fat = val;
                return this;
            }
            //返回一个不可变的NutritionFacts
            public NutritionFacts build(){
                return new NutritionFacts(this);
            }
       }
      
       private NutritionFacts(Builder builder){
             servings = builder.servings;
             calories = builder.calories;
             fat = builder.fat;
       }
 }

优点:builder像构造器一样,可以对参数强加约束条件。有多少个可变参数,就可以根据需要设置多少可变参数

缺点:构建器模式的开销比构造器大,在某些是否注重性能的情况下,可能成为问题。

总结:如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是种不错的选择,特别是当大多数参数都是可选的时候。与使用传统的重叠构造器相比,使用Builder模式的代码更易于阅读和编写,也比JavaBean更加安全。

Tips:为什么代码易于阅读和编写是个优点,编写代码很大情况是再理解别人写的代码逻辑和意图,甚至是自己写的,所以易于阅读的代码能提高你的编码或者别人的编码效率,推荐大家看《clean code》这本书。