静态工厂和构造器共同的局限性,就是都不能很好的扩展到大量的可选参数。有一些场景中的类字段一部分字段是必须的,一部分字段是可选的,这种场景很常见。
public class Cat {
private Integer id;// id 必要字段
private String name;// 名称 必要字段
private Integer age;// 年龄 必要字段
private BigDecimal price;// 价格 必要字段
private Double height;// 身高 可选字段
private Double weight;// 体重 可选字段
public Cat() {
}
- 很常见的操作就是使用重叠构造器的方式,提供一个只有必要参数的构造器,其他构造器做另外的定制化。简单来说,重叠构造器的方式看似可行,但是如果参数过多的情况下。不仅写比较麻烦,别人读也比较难受。如果看代码的人想要知道这些值是什么意思,需要根据顺序数第几个参数是什么意思,如果有很多相同类型的参数,就很容易出错。
public class Cat {
private Integer id;// id 必要字段
private String name;// 名称 必要字段
private Integer age;// 年龄 必要字段
private BigDecimal price;// 价格 必要字段
private Double height;// 身高 可选字段
private Double weight;// 体重 可选字段
public Cat() {
}
/**
* 必要参数构造器
*/
public Cat(Integer id, String name, Integer age, BigDecimal price) {
this(id, name, age, price, null, null);
}
/**
* 除了必要参数增加一个身高字段等
*/
public Cat(Integer id, String name, Integer age, BigDecimal price, Double height) {
this(id,name,age,price,height,null);
}
public Cat(Integer id, String name, Integer age, BigDecimal price, Double height, Double weight) {
this.id = id;
this.name = name;
this.age = age;
this.price = price;
this.height = height;
this.weight = weight;
}
}
- 还有另一种方式就是通过setter方法来将每个必要的参数和可选的参数进行赋值。弥补了重叠构造器的不足,并且代码阅读起来也容易一些。缺点就是:构造过程被分成了几个方法中,在set的过程中可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性(可能这一点没有理解的很清楚,看不太懂!)
- 通过建造者模式来创建对象,既能保证像重叠构造器模式的安全性(链式编程,一次调用多个方法),也能保证像Setter方法那样好的可读性。并且在build的过程中可以增加必要参数是否赋值的校验来做定制化操作 如果类的构造器或者静态工厂中有多个参数,Builder模式是不错的选择
public class Cat {
private Integer id;// id 必要字段
private String name;// 名称 必要字段
private Integer age;// 年龄 必要字段
private BigDecimal price;// 价格 必要字段
private Double height;// 身高 可选字段
private Double weight;// 体重 可选字段
public static class CatBuilder{
private Integer id;// id 必要字段
private String name;// 名称 必要字段
private Integer age;// 年龄 必要字段
private BigDecimal price;// 价格 必要字段
private Double height;// 身高 可选字段
private Double weight;// 体重 可选字段
public CatBuilder id(Integer id){
this.id = id;
return this;
}
public CatBuilder name(String name){
this.name = name;
return this;
}
public CatBuilder age(Integer age){
this.age = age;
return this;
}
public CatBuilder price(BigDecimal price){
this.price = price;
return this;
}
public CatBuilder height(Double height){
this.height = height;
return this;
}
public CatBuilder weight(Double weight){
this.weight = weight;
return this;
}
public Cat build(){
if(Objects.isNull(id)){
throw new IllegalArgumentException("CatBuild.id is not null! ");
}
if(Objects.isNull(name)){
throw new IllegalArgumentException("CatBuild.name is not null! ");
}
if(Objects.isNull(age)){
throw new IllegalArgumentException("CatBuild.age is not null! ");
}
if(Objects.isNull(price)){
throw new IllegalArgumentException("CatBuild.price is not null! ");
}
return new Cat(this);
}
}
public Cat(CatBuilder builder) {
id = builder.id;
name = builder.name;
age = builder.age;
price = builder.price;
height = builder.height;
weight = builder.weight;
}
}