《EffectiveJava》读后感(第2章创建和销毁对象 第2条)

遇到多个构造器参数时要考虑使用构建器(Builder设计模式)

静态工厂和构造器有个共同的局限性:它们都不能很好的扩展到大量的可选参数。考虑用一个表示包装食品外显示的营养成分标签。这些标签中有几个域是必须的:每份的含量、每罐的含量以及每份的卡路里,还有超过20个可选域:总脂肪量、饱和脂肪量、转化脂肪、胆固醇、钠等等。大多数产品在某几个可选域中都会有非零的值。

  1. 重叠构造器方式
    一般创建构造器会使用重叠构造器的方式,即首先创建一个只有必要参数的构造器,然后第二个构造器有一个可选参数,第三个构造器有两个可选参数,依此类推,最后一个构造器包含所有的可选参数。

这种方法虽然可行,但是客户端代码编写起来十分麻烦,因为需要十分小心的辨别每个参数。

  1. JavaBeans方式
    这种模式下,调用一个无参的构造器来创建对象,然后用setter方法去设置每个必要的参数,以及每个相关的可选参数。

这种方式比重叠构造器方式创建实例更加容易,可读性也更高
但是缺点就在于因为构造过程被分到了几个调用中,所以无法保证一致性,阻止了把类做成不可变的可能,需要程序员付出额外的努力来确保线程安全。

  1. Builder方式
    如何既能做到像重叠构造器方式保证数据的一致性,又能有JavaBeans方式的可读性呢,第三种替代方式:Builder方式可以做到

不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器,得到一个Builder对象。
然后客户端在Builder对象上调用setter方法,来设置每个相关的可选参数。
最后调用Builder无参的build方法来生成不可变的对象。

如下例:

public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int fat;
    private final int sodium;

    public static class Builder {
        //Required parameters
        private final int servingSize;
        private final int servings;
        //Optional parameters
        private int fat = 0;
        private int sodium = 0;

        public Builder (int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder fat(int fat) {
            this.fat = fat;
            return this;
        }

        public Builder sodium(int sodium) {
            this.sodium = sodium;
            return this;
        }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        fat = builder.fat;
        sodium = builder.sodium;
    }
}

客户端的调用可以采用如下形式:

 public static void main(String[] args) {
        NutritionFacts nutritionFacts = new NutritionFacts.Builder(230, 9)
                .fat(100)
                .sodium(35)
                .build();
    }

当然builder模式也有自身的不足,为了创建对象,必须先创建它的构建器。虽然创建构建器的开销在实践中可能并不那么明显,但是在某些十分注重性能的情况下,可能就成为问题了。Builder模式还比重叠构建器模式更加冗长,因此它只在有很多参数的时候才使用,比如4个或者更多个参数的情况下。但是如果后期还会添加参数的时候才添加构建器就有点无法控制了,那些过时的构建器或者静态工厂就会显得不协调。因此,通常在一开始就使用构建器。

在上家公司的项目中就要求添加参数时必须使用Builder模式(不然无法提交代码),其目的时为了使属性在使用过程中保证属性不会被修改,保证类数据的安全性。

简而言之,如果类的构建器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是一种很不错的选择,特别是当大多数都是可选的时候。与使用重叠构造器相比,使用Builder模式的客户端将更易于阅读和编写,构建器也比JavaBean更加安全。

展开阅读全文
©️2020 CSDN 皮肤主题: 游动-白 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值