当一个类具有多个可选域时(如对于Person,名字是必须的,其他可选),会出现多个重叠构造器,如下
class Person {
private String name;
private int age;
private int height;
private int weight;
public Person(String name) {
this(name, 0);
}
public Person(String name, int age) {
this(name, age, 0);
}
public Person(String name, int age, int height) {
this(name, age, height, 0);
}
public Person(String name, int age, int height, int weight) {
this.name = name;
this.age = age;
this.height = height;
this.weight = weight;
}
}
当想创建实例时,需要不得不对本不需要设置的域设置值,如下只想对name、height和weight赋值,但不得不对age也赋值
Person person = new Person("song", 0, 170, 52);
与此同时,当域数量增多时,需要仔细查看每一个域的位置和用途,以避免错误的设置顺序
利用javabean,可先用无参构造器生成空对象,再用setter方法来为需要的参数赋值
class Person {
private String name;
private int age;
private int height;
private int weight;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
创建实例
Person person = new Person();
person.setName("song");
person.setHeight(170);
person.setWeight(52);
javabean将类的构造过程分成了多个步骤,在构造过程中对象的状态可能处于不一致的状态,即并发修改,为避免出现这样的情况,需要额外的加锁操作
采用构建器模式,并不直接生成想要的实例,而是先构造一个Builder,利用Builder来为所需的参数赋值,最后再设置到实例中去
class Person {
private String name;
private int age;
private int height;
private int weight;
public Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.height = builder.height;
this.weight = builder.weight;
}
public static class Builder {
private String name;
private int age = 0;
private int height = 0;
private int weight = 0;
public Builder(String name) {
this.name = name;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder height(int height) {
this.height = height;
return this;
}
public Builder weight(int weight) {
this.weight = weight;
return this;
}
public Person build() {
return new Person(this);
}
}
}
创建实例
Person person = new Person.Builder("song").height(170).weight(52).build();
利用Builder可单独为每个参数赋值,从而实现可选参数的设定
如下是奶茶抽象类
利用enmu规定配料,Set记录添加的配料
EnumSet记录Builder添加的配料
addTopping()添加配料返回Builder
build()和self()为抽象类由子类实现
abstract class MilkTea {
public enum Topping {Pudding, Pearl, Sago}
private final Set toppings;
abstract static class Builder> {
private EnumSet toppings = EnumSet.noneOf(Topping.class);
public T addTopping(Topping topping) {
toppings.add(topping);
return self();
}
abstract MilkTea build();
protected abstract T self();
}
MilkTea(Builder> builder) {
toppings = builder.toppings.clone();
}
}
如下是其实现类
利用enmu规定大小
重写父类的build()和self()返回自身的实例和Builder
class GreenTea extends MilkTea {
public enum Size {Small, Medium, Large}
private final Size size;
public static class Builder extends MilkTea.Builder {
private final Size size;
public Builder(Size size) {
this.size = size;
}
@Override
GreenTea build() {
return new GreenTea(this);
}
@Override
protected Builder self() {
return this;
}
}
private GreenTea(Builder builder) {
super(builder);
size = builder.size;
}
}
创建实例
GreenTea greenTea = new GreenTea.Builder(GreenTea.Size.Small).addTopping(MilkTea.Topping.Pudding).addTopping(MilkTea.Topping.Pearl).build();