effective java 之遇到多个构造器参数时要考虑用构建器
一个类有多个参数,我们如何获得该类的对象?有三种解决方案可以处理这种问题。
采用重叠构造器
JavaBeans模式
Builder模式
1、重叠构造器
重叠构造器:就是提供多个多个参数列表不同构造函数。一般我们遇到多个参数时候,就会考虑使用重叠构造器,
第一个构造器是实例化对象必须的参数,第二个会多一个参数,就这样叠加,最后是一个有所有参数的构造器。
当参数非常多的时候,如此下去后果难以想象。
public class Person {
//必须字段
private String name;
private int age;
//可选字段
private String address;
private String phone;
public Person(String name, int age) {
this(name,age);
}
public Person(String name, int age, String address) {
this(name,age,address);
}
public Person(String name, int age, String address, String phone) {
super();
this.name = name;
this.age = age;
this.address = address;
this.phone = phone;
}
.....
}
当进行对象调用时,难以编程,不宜阅读,难以维护。
2、JavaBeans模式
当重叠构造器难以使用,这个时候我们还有一种替代的方式,这个就是JavaBeans模式。
这种模式下,使用无参的构造方法创建对象,然后调用setter 方法给属性设置值。
public class Person {
private String name;
private int age;
private String address;
private String phone;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
使用的方式,这个相比与重叠构造器更容易的创建了对象,同时让代码跟容易的阅读。
2.1 JavaBeans模式的劣势
构造的过程分到了几个调用中,在构造JavaBeans的时候可能会不一致.
类无法仅仅通过检验构造器参数的有效性来保证一致性!
对象的不一致会导致失败,JavaBeans模式阻止了把类做为不可变的可能,需要程序员做额外努力来保证它线程安全。
3、Builder(设计模式一节会有更深的认识)
3.1什么是构建器
构建器也是一种获得类对象的方法。下面的实例就是调用构建器获得对象实例。
静态工厂方法与构造器都有一个共同的局限性,就是它们不能很好的扩展到大量的可选参数。
就上面的那个Person 类,在实际中会有许多的可选属性,性别、出生年月、爱好...。
public class Person {
// 必须字段
private String name = "";
private int age = 0;
// 可选字段
private String address = "";
private String phone = "";
// 构建器
public static class Builder {
private String name = "";
private int age = 0;
private String address = "";
private String phone = "";
//必选字段
public Builder(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Builder address(String val) {
address = val;
return this;
}
public Builder phone(String val) {
phone = val;
return this;
}
public Person builder() {
return new Person(this);
}
}
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.address = builder.address;
this.phone = builder.phone;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address
+ ", phone=" + phone + "]";
}
}
buidler模式是利用了一个静态的内部类来生成一个中间对象,然后利用类似JavaBeans的模式来获取到所有所需的参数,再来调用目标类的构造函数。
3.2 调用构建器
public static void main(String[] args) {
// 两个可选参数都不选
Person p1 = new Person.Builder("李四", 20).builder();
// 一个可选参数
Person p2 = new Person.Builder("李四", 20).address("深圳").builder();
//带多个参数
Person p3 = new Person.Builder("李四", 20).address("深圳").phone("10086")
.builder();
System.out.println(p1.toString());
System.out.println(p2.toString());
System.out.println(p3.toString());
}
3.3 构建器优势
构建器的创建对象就比较易于创建与阅读,线程安全。
等待所有的参数验证通过才会build()对象。
与构造器相比,builder 的微略优势在,builder可以有多个可变(varargs)参数。构造器像方法一样,只有一个可变参数。因为builder利用单独的方法来设置每个参数,你想要多少个可变参数,他们就可以有多少个,知道每个setter方法都有一个可变参数。
builder模式非常灵活,可以利用单个builder构建多个对象。builder的参数可以在创建对象时进行调整。
设置了参数的builder生成一个很好的抽象工厂(Abstract Factory),也就是客户端可以将这样一个builder传给方法,使该方法能为客户端创建一个或者多个对象。
与重叠构造器相比,builder模式的客户端更易与阅读和编写。
与JavaBeans相比,更加的安全。
3.4 构建器不足
就是创建对象就必须创建它的构建器。虽然创建构建器的开销在实践中可能不是很明显,但是在注意性能的情况下,这个就是问题了。
builder模式还比重叠构造器模式更加的冗长,因此它只会在参数多的时候使用。但是我们要知道,我们可能会在设计之后还要添加参数,所以已开始就用构建器还是比较好的。
每天努力一点,每天都在进步。