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

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

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

当遇到大量的可选参数时候,一般的处理方式是重载构造方法

重载构造器模式可行,但是当有许多参数的时候,客户端代码很难编写,并且难以阅读

一长串类型相同的参数会导致一些微妙的错误,如果客户端不小心颠倒了其中两个参数的顺序,编译器也不会出错,但是程序在运行的时候回出现一些错误的行为

  • 替代方式一
    即JavaBean模式,在这种模式下调用一个误餐构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数
 Person mPerson = new Person();
    mPerson.setName("bob");
    mPerson.setAge(10);
    mPerson.setProfession("doctor")
    ...

遗憾的是javaBean模式自身有着很严重的缺点,因为构造过程被分割到好多个set中容易造成线程不安全,导致对象处于不一致的状态

  • 替代方式二
    既能保证像重叠模式那样的安全,也能保证像javaBeans模式那么好的可读性,这就是builder模式的一种形式
public class NutritionFacts {
    private int servingSize ;
    private int servings ;
    private int calories;
    private int fat ;
    private int sodium ;
    private int 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.servings = servings;
            this.servingSize = servingSize;
        }

        public Builder calories(int val) {
            calories = val;
            return this;
        }
        public Builder carbohydreate(int val){
            carbohydrate = val;
            return this;
        }
        public Builder sodium(int val){
            sodium = val;
            return this;
        }
        public Builder fat(int val){
            fat = 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;
        carbohydrate = builder.carbohydrate;
    }
}

所有的默认参数值都单独放在一个地方,builder的setter方法返回其本身,这样就可以把调用连接起来,客户端代码如下:

  NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).
                calories(100).sodium(35).build();

这样的客户端代码很同意编写,跟为重要的是,易于阅读,builder模式模拟了具体名字的可选参数
builder像个构造器一样,可以对其参数强加约束条件,builder方法可以检验这些约束条件,将参数从builder拷贝到对象中之后,并在对象域而不是builder域中对他们进行检验,如果违反了任何约束条件,builder方法就应该抛出ILLegalStateException,异常的详细信息应该显示出违反了那个约束条件

你可能感兴趣的:(第二条 遇到多个构造器参数时要考虑用构建器)