`
chenhuachong
  • 浏览: 2881 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

Effective Java 学习 第二条 使用构建器

阅读更多

1.问题背景

有这样一个背景:考虑到用一个类描述产品的成分说明书。在成分说明书中,某些标签是必需的:成分A,成分B,另外还有其他可选成分,成分C,成分D,成分E......对于这样的类,如果使用构造器来完成类对象的构造的话,是相当复杂的,因为你可能需要写许多的构造方法以满足不同产品的成分说明。

2.重叠构造器模式

在以上背景下,程序猿一般会采用重叠构造起模式。实例如下:

public class Product{
    private final int proElem1;// 成份1,必需参数
    private final int proElem2;//成份2,必需参数
    private final int proElem3;//成份3,可选参数
    private final int proElem4;//成份4,可选参数
    public Product(int proElem1,int proElem2){
        this.proElem1 = proElem1;
        this.proElem2 = proElem2;
        this(proElem1,proElem2,0,0);
    }
    public Product(int proElem1,int proElem2,int proElem3){
        this(proElem1,proElem2,proElem3,0);
    }
    public Product(int proElem1,int proElem2,int proElem3,int proElem4){
        this.proElem1 = proElem1;
        this.proElem2 = proElem2;
        this.proElem3 = proElem3;
        this.proElem4 = proElem4;
    }
}
你创建实例的时候就可以根据自己需要的参数创建不同的实例。上面的程序一定程序上可以使得创建实例更加清晰,但是想象一下如果类需要设置的参数特别多的情况,客户端代码会很难编写,而且比较难以阅读,如果客户端不小心颠倒了参数的顺序,编译器可能也不会出错。当遇到许多构造器参数的时候可以考虑以下方案。

3.JavaBeans模式

在这种模式下,使用一个无参的构造器来创建实例,然后使用属性的setter方法来设置属性的值,实例如下:

public class Product{
    private int proElem1;
    private int proElem2;
    private int proElem3;
    private int proElem4;
    public Product(){
    }
    public void setProElem1(int proElem1){
        this.proElem1 = proElem1;
    }
    public void setProElem2(int proElem2){
        this.proElem2 = proElem2;
    }
    public void setProElem3(int proElem3){
        this.proElem3 = proElem3;
    }
    public void setProElem4(int proElem4){
        this.proElem4 = proElem4;
    }
}
这种模式弥补了重叠构造器模式的不足,使得创建实例更加容易。

JavaBeans模式的缺点:实例的创建被分成了几个阶段,使得实例在程序中处于一种不一致的状态(我随时都可以设置实例的属性)。幸运的是,还有第三种方法!

3.建造者模式

建造者模式既可以像重叠构造器那么安全,又能保证像JavaBeans那样的可读性。使用Builder模式,不直接生成对象,而是让客户端利用必要的参数调用构造器,得到一个builder对象,然后在builder对象上调用类似setter的方法,来设置参数,实例如下:

public class Product{
    private final int proElem1;
    private final int proElem2;
    private final int proElem3;
    private final int proElem4;
    public static class Builder{
        private final int proElem1;
        private final int proElem2;
        private int proElem3;
        private int proElem4;
        public Builer(int proElem1,int proElem2){
            this.proElem1 = proElem1;
            this.proElem2 = proElem2;
        }
        public Builder proElem3(int proElem3){
            this.proElem3 = proElem3;
            return this;
        }
        public Builder proElem4(int proElem4){
            this.proElem4 = proElem4;
            return this;
        }
        public Product build(){
            return new Product(this);
        }
    }
    private Product(Builder builder){
        proElem1 = builder.proElem1;
        proElem2 = builder.proElem2;
        proElem3 = builder.proElem3;
        proElem4 = builder.proElem4;
    }
}
使用Builder模式创建对象的优点:

1、客户端代码更容易编写,builder模式模拟了具名的可选参数,设置参数更加清晰;

2、通过build方法可以对参数进行约束,如果不满足条件可以抛出异常;

3、设置了参数的builder生成了一个很好的抽象工厂;

备注:定义一个范型就可以满足所有的builder

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

4.总结

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





版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics