Effective Java - 创建和销毁对象 - 遇到多个构造器参数时要考虑用构建器

本文对比了静态工厂、重叠构造器、JavaBeans及Builder四种构造模式的优缺点,着重介绍了每种模式的应用场景及其可能导致的问题。

读书笔记 仅供参考

静态工厂和构造器的局限性

不能很好地扩展到大量的可选参数

重叠构造器模式

提供一个只有必要参数的构造器,其余构造器逐渐增加可选参数,直到最后一个构造器包含所有可选参数

public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    //两个必要参数
    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 = servingSize;
        ...
        this.sodium = sodium;
    }
}

随着参数的增加,程序很快会失去控制,客户端代码会很难编写,并且难以阅读。

JavaBeans 模式

即利用 setter 和 getter 方法来设置参数,我从最开始写 java 代码就使用这种方式。这种方式与前后两种还有一个区别:属性不能设为 final,即不可作为不可变类。

public class NutritionFacts {
    private int servingSize;
    private int servings;
    private int calories;
    private int fat;
    private int sodium;
    public void setServingSize(int servingSize) {
        this.servingSize = servingSize;
    }
    ...
}

因为构造过程被分到多个调用中,在构造过程中 JavaBeans 可能处于不一致的状态,试图使用不一致状态的对象,将会导致失败。另外一点不足:JavaBeans 模式组织了将类作为不可变类的可能,需要付出额外努力确保线程安全
ps:不一致的状态:不是很理解这个概念,在网上查询的结果是:同一个构造器产生的对象,但是最后对象的属性却大相径庭。或者理解为,在还没有为对象 set 必要属性的时候,就使用对象,会导致错误(这个倒是我时常会发生的错误)。

Builder 模式

先产生一个 builder 对象,再在 builder 对象上调用类似 setter 的方法,设置可选参数,最后利用无参的 build 方法生成不可变的对象。

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 servingSize;
        private final int servings;
        //可选参数,要有默认值
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }
        public Builder calories(int val) {
            caolries = val;
            return this;
        }
        public Builder fat(int val) {
            fat = val;
            return this;
        }
        public Builder sodium(int val) {
            sodium = val;
            return this;
        }
        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }
    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        ...
    }
}

//调用方式
NutritionFacts fact = new NutritionFacts.Builder(240, 8).
    calories(100).sodium(35).build();

builder 可以对参数进行检验,如果违反了约束就抛出异常。也可以在 setter 方法(builder 模式的 setter)中对参数进行检验,不在 builde() 方法中检验。
设置了参数的 builder 生成了一个抽象工厂,用泛型满足所有的 builder

public interface Builder<T> {
    public T build();
}

Builder 模式的不足在于创建 builder 的性能损耗,在十分注重性能的情况下,会成为问题, Builder 模式比重叠构造器还冗长,所有只有在有很多参数的情况下才使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值