无论是静态工厂还是构造器都有共同的局限性:它们都不能很好地扩展到大量可选参数。
然后重叠构造器模式可以实现这一需求,但是又许多参数的时候,客户端代码会变得很难编写,并且可读性很差
于是我们想到JavaBean模式,在这种模式下,调用一个无参构造器来创建对象,然后使用setter来对每个参数进行设置,例:
Book book = new Book();
book.setName("xx");
book.setPrice(123);
这样就出现了一个问题,由于对Book类的参数设置是多个setter方法,这个类可能会处于不一致状态,会导致难以调试的错误。
因此我们说JavaBeans模式阻止了把类做成不可变的可能(即不能做到线程安全)
那么我们会想,有没有一种模式既能保证像JavaBeans模式那样的可读性,又能保证像重叠构造器模式那样的安全性?
有,那就是Builder模式
Builder模式的做法:
1.这个模式不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个builder对象。
2.然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调用build()方法来生产不可变对象。
下面是Book的Builder模式的代码
public class Book{
private String name;
private float price;
private String authorName;
//这里有很多参数没写出来
//这是Builder,Book类的内部类
public static class Builder{
private String name;
private float price;
private String authorName;
//这是Builder的狗构造器
public Builder(){
}
//Builder的setter方法,注意这里返回值是自身,链式编程
public Builder name(String val){
name = val;
return this;
}
//这里有很多参数的setter没写出来
//还有一个重要方法,builder方法,用于生成真正的对象,这里是Book的实例
public Book builder(){
return new Book(this);
}
}
//这是Book的构造器,只接受一个参数,那就是已经构建好的builder
private Book(Builder builder){
name = builder.name;
price = builder.price;
//这里有很多赋值没写出来
}
}
以下是客户端代码:
Book book = new Book.Builder().name("书名").price(12).省略.builder();
注意:Builder模式的参数校验应该放在setter方法中,而不是在builder()方法中。
当然,Builder模式也有自身的不足,因为每次为了创建对象,都要先创建Builder的狗构造器。
在某些十分注重性能的情况下,可能会发生问题。
并且,最好在类设计时一开始就是用Builder,而不是构造器和Builder共存
简而言之,如果类的构造器或静态工厂中具有多个参数,设计这种类时,Builder模式是不错的选择,特别是当大多数参数是可选的时候。