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

  由于静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。因此我们下面要来说说构建器,所谓的构建器其实就是具有创建外部类功能的内部静态类。首先我们先理解几个模式

  1.重叠构造器模式

    提供一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个构造器有两个可选参数,依次类推,直到最后一个构造器包含所有的可选参数。

    缺点:谁作为第一个可选参数是一个问题,因为后一个包含两个可选参数的构造器必须传递值给第一个可选参数,导致需要设置许多本不想设置的参数。

  2.JavaBean模式

    通过一个无参构造器创建对象,然后调用setter方法来设置每个必要的参数。这样创建实例很容易,产生的代码读起来也比较容易,因为通过setter的方法名能知道设置的参数是哪一个。

    缺点:构造过程被分到了几个调用之中,在构造过程中无法保证JavaBean的一致性。

  3.Builder模式(本条主要)

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

  

  好了,下面就让我们来看看具体的构建器的做法:

public class BuilderObject {
        private final String filed01;
        private final String filed02;
        private final String filed03;
        private final String filed04;
        private BuilderObject(Builder builder){
            this.filed01 = builder.filed01;
            this.filed02 = builder.filed02;
            this.filed03 = builder.filed03;
            this.filed04 = builder.filed04;
        } 
        //构建器(内部类)
        public static class Builder{
            private String filed01;
            private String filed02;
            private String filed03;
            private String filed04;
            public Builder filed01(String filed01){
                this.filed01 = filed01;
                return this;
            }
            public Builder filed02(String filed02){
                this.filed02 = filed02;
                return this;
            }
            public Builder filed03(String filed03){
                this.filed03 = filed03;
                return this;
            }
            public Builder filed04(String filed04){
                this.filed04 = filed04;
                return this;
            }
            public BuilderObject build(){//build方法,生成一个需要被构建的类
                return new BuilderObject(this);
            }
        }
}

  使用的时候我们只需要按照自己的意愿来添加即可:

BuilderObject builderObject = new BuilderObject.Builder()
                                      .filed01("filed01")
                                      .filed02("filed02")
                                      .filed03("filed03")
                                      .filed04("filed04")
                                      .build();

  那我们应该在什么时候使用构建器呢?如果有一个类有很多个参数filed01、filed02、filed03、filed04、filed05、filed06......其中有些必填有些非必填。这时候我们如果选择构造器(我们少选点参数来举例,就选择filed01、filed02、filed03,其中就filed01必填,另外两个选填)的话,就如下:

public MyObject(String filed01, String filed02, String field03) {
        this.filed01 = filed01;
        this.filed02 = filed02;
        this.field03 = field03;
}
public MyObject(String filed01, String filed02) {
        this(filed01, filed02, null);
}
public MyObject(String filed01) {
        this(filed01, null, null);
}

  那么如果有更多的参数就需要更多的构造方法了,显然很不科学。同理静态工厂方法也是不合理的,这时候有人可能会说,用Javabean方式不就可以了么?给每个属性设置setter/getter方法,看似好像这种方法好像解决了上述问题,但是!javabean模式有一个致命的缺陷,就是它的构造过程分部到几次调用中,而不是一次性完成的。也就是说三个字段我需要使用三次setter方法,而不是一次性完成。这意味着什么呢?意味着它有可能在构造的过程中被改变,这一点在多线程、高并发的程序中显得尤为重要。不仅如此,javabean模式还有第二个缺点:如果对象中含有final修饰的字段,那么javabean模式将不能对其执行setter操作。

  总结:

    如果类的构造器或是静态工厂方法中具有多个参数,设计这种类时,使用Builder方式(构建器方式)就是种不错的选择,特别是当大多是参数都是可选的时候。与使用传统的重叠构造器模式相比,使用Builder模式的客户端代码将更容易阅读和编写,构建器也比javabean更加安全。

  

 

posted @ 2017-04-11 13:54  哀&RT  阅读(403)  评论(0编辑  收藏  举报