如何应对大量参数的构造器?
在开发过程中,经常会有很多数量的参数传进类的构造器,有一种很简单的做法是把这些参数都放到构造器中作为形参,例如下面的一个例子:
class Employee {
private String company;
private int salary;
private String name;
private int height;
private int weight;
private String gender;
public Employee(String company,
int salary,
String name,
int height,
int weight,
String gender) {
this.company = company;
this.salary = salary;
this.name = name;
this.height = height;
this.weight = weight;
this.gender = gender;
}
//通过重叠构造器的方式,创建默认company为"Oracle"的员工
public Employee(int salary,
String name,
int height,
int weight,
String gender) {
this("Oracle", salary, name, height, weight, gender);
}
}
上面的例子中,有两个构造器,第一个把所有的参数都包含,第二个通过重叠构造器的方式创建默认公司为“Oracle”的对象,这样的方式会带来一个问题:
- 代码可读性差,客户很容易就弄乱了参数的传入顺序,造成难以发现的bug.
除了上述方法,还可以通过Java Bean的方式, 也就是通过getter和setter来把参数一个一个传入。如:
Person person = new Person();
person.setName("Jimmy");
person.setHeight(175);
.....//省略
遗憾的是,通过Java Bean的方式传入参数也会带来一个问题:
- 因为构造过程被分到了几个调用中,对象在构造过程中可能处于不一致的状态。这需要额外的努力来确保它的线程安全。
Builder(建造器)模式
Builder模式可以解决以上两种方式的缺点,而且既能保证像构造器模式那样的安全性,也能保证像Java Bean模式那么好的可读性。
class Employee {
private final String company;
private final int salary;
private final String name;
private final int height;
private final int weight;
private final String gender;
public static Builder {
private String company = "Oracle";
private final int salary;
private final String name;
private final int height;
private final int weight;
private final String gender;
public Employee build() {
return new Employee(this);
}
public Builder setSalary(int salary) {
this.salary = salary;
}
public Builder setName(String name) {
this.name = name;
}
//.....省略
}
private Employee(Builder builder) {
company = builder.company;
salary = builder.salary;
//......省略
}
}
通过builder模式新建对象如下:
Employee mEmployee = new Employee.Builder()
.setSalary(10000)
.setName("Jimmy")
.build();
当然builder模式因为需要新建一个builder对象,从而造成内存消耗,在实 际开发中,创建大量对象时需要衡量一下。