Effective Java

来源:互联网 发布:jquery定义数组并赋值 编辑:程序博客网 时间:2024/06/05 17:41

读书笔记 仅供参考

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

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

重叠构造器模式

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

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 模式比重叠构造器还冗长,所有只有在有很多参数的情况下才使用。

原创粉丝点击