情景需要:
假设有这样一个Human类,要构造一个Human对象必须传递6个参数,其中前3个是必须的,后3个是可选的:
- classHuman{
- //requiredparameters
- privatefinalStringname;
- privatefinalStringgender;
- privatefinalintage;
- //optionalparameters
- privatefinalintheight;
- privatefinalintweight;
- privatefinalStringcountry;
- }
那么,给这个类设计构造方法会是比较头疼的事。
一种方案是,我们可以设计一个有6个参数的构造方法,分别给name, gender, height, weight, country赋值,其中后3个值可以有缺省值。如:
- publicHuman(Stringname,Stringgender,intage,intheight=180,intweight=50,Stringcountry="China"){
- //......
- }
然而这样设计有一个不足之处,那就是后3个参数虽然有缺省值,但参数的顺序是固定的,不能变的,如果用户在传参的时候把顺序搞错了,就会产生错误。而且如果参数类型相同的话,编译器也不会报错。为了弥补这样的不足,我们可以重载构造方法,如:
- publicHuman(Stringname,Stringgender,intage){}
- publicHuman(intheight){}//不能构成重载
- publicHuman(intweight){}//不能构造重载
- publicHuman(Stringcountry){}
这样虽然解决了参数顺序的问题,但如果这个类的可选参数有不只3个,比如有6个,10个,20个的话,那么就要设计大量的重载的方法,非常费事。而且上面的代码还存在一个问题,那就是第2个和第3个方法根本无法构成重载。也就是说,当可选参数的参数类型有重复的时候,上面的设计方法就不可行了。
这时候我们就可以采用 Builder模式 来解决这样问题。
Builder模式
我们可以在Human的内部定义一个静态的内部类Builder,通过这个类来完成对参数的赋值工作,如:
class Human {
// required parameters
private final String name;
private final String male;
private final int age;
// optional parameters
private final int height;
private final int weight;
private final String country;
// builder class
public static class Builder {
// required parameters
private final String name;
private final String male;
private final int age;
// optional parameters
private int height = 0;
private int weight = 0;
private String country = "none";
public Builder(String name, String male, int age) {
this.name = name;
this.male = male;
this.age = age;
}
public Builder setHeight(int h) {
this.height = h;
return this;
}
public Builder setWeight(int w) {
this.weight = w;
return this;
}
public Builder setCountry(String c) {
this.country = c;
return this;
}
public Human build() {
return new Human(this);
}
}
}
然后为Human提供一个私有的构造方法,以Builder对象作为其形参,在此构造方法中完成参数的赋值:
- privateHuman(Builderb){
- name=b.name;
- gender=b.gender;
- age=b.age;
- height=b.height;
- weight=b.weight;
- country=b.country;
- }
这样一来,用户 在使用Human 这个类的时候,就可能以如下的方式来构造Human对象:
- Humanhm=newHuman.Builder("bruce","male",20)//设置必须参数
- .setCountry("China")//设置可选参数
- .setWeight(50)//设置可选参数
- .build();//构造对象
显然,Human类的使用者在创建其对象时所写的代码就变得简单明了多了。
因此,当一个类的构造方法必须传递大量参数的时候,我们可以考虑使用Builder模式来构造此类。当应用程序对性能要求不是很高时,Builder模式是处理此类情形的最好方案。