参考资料
应用场景
- 把类的必填属性放到构造函数中,强制创建对象的时候就设置。如果必填的属性有很多,把这些必填属性都放到构造函数中设置,那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置,那校验这些必填属性是否已经填写的逻辑就无处安放了。
- 如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造函数配合 set() 方法的设计思路,那这些依赖关系或约束条件的校验逻辑就无处安放了。
- 如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。
建造者模式实现方式
场景:
- name是必需字段
- 配置项直接有依赖关系:
- 如果设置了 maxTotal、maxIdle、minIdle 其中一个,就必须显式地设置另外两个
- maxIdle 和 minIdle 要小于等于 maxTotal。
- ResourcePool是不可变对象,创建后不可再通过setter方法修改属性
public class ResourcePool{
private String name;
private int maxTotal;
private int maxIdle;
private int minIdle;
private ResourcePool(Builder builder){
this.name = builder.name;
this.maxTotal = builder.maxTotal;
this.maxIdle = builder.maxIdle;
this.minIdle = builder.minIdle;
}
//省略getter方法
//不要setter方法
//这里将Builder类设计成了ResourcePool的内部类。
//也可以将Builder类设计成独立的非内部类ResourcePoolBuilder。
public static class Builder{
private static final int DEFAULT_MAX_TOTAL = 8;
private static final int DEFAULT_MAX_IDLE = 8;
private static final int DEFAULT_MIN_IDLE = 0;
private String name;
private int maxTotal = DEFAULT_MAX_TOTAL;
private int maxIdle = DEFAULT_MAX_IDLE;
private int minIdle = DEFAULT_MIN_IDLE;
public ResourcePoolConfig build(){
// 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等
if (StringUtils.isBlank(name)){
throw new IllegalArgumentException("...");
}
if (maxIdle > maxTotal){
throw new IllegalArgumentException("...");
}
if (minIdle > maxTotal || minIdle > maxIdle){
throw new IllegalArgumentException("...");
}
return new ResourcePool(this);
}
public Builder setName(String name){
if (StringUtils.isBlank(name)){
throw new IllegalArgumentException("...");
}
this.name = name;
return this;
}
public Builder setMaxTotal(int maxTotal){
if (maxTotal <= 0){
throw new IllegalArgumentException("...");
}
this.maxTotal = maxTotal;
return this;
}
public Builder setMaxIdle(int maxIdle){
if (maxIdle < 0){
throw new IllegalArgumentException("...");
}
this.maxIdle = maxIdle;
return this;
}
public Builder setMinIdle(int minIdle){
if (minIdle < 0){
throw new IllegalArgumentException("...");
}
this.minIdle = minIdle;
return this;
}
}
}
建造者模式还可以避免对象短暂的无效状态。
与工厂模式的区别
- 工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。
- 建造者模式是用来创建一种类型的复杂对象,通过设置不同的可选参数,“定制化”地创建不同的对象。