直接使用构造函数或者配合set方法就能创建对象,为什么还需要建造者来创建?建造者和工厂模式都可以创建对象,他们两者区别是什么
为什么需要建造者模式
假设场景:需要定义资源配置类ResourcePoolConfig,这里的资源池就好比是线程池、连接池、对象池。在这个资源配置类中有以下配置项
存在问题:
- name为必填项,可以放到构造函数中,但是如果必填项很多构造函数参数就会很多,如果必填项通过set()方法设置那校验这些必填逻辑就无处安放。
- 假设这些配置项之间有依赖关系,比如设置了maxTotal、maxIdle、minIdle其中一项就必须显示设置另外两项,那这些校验逻辑在哪设置
- 如果希望ResouPoolConfig是不可变对象,创建好后不能改变内部属性,那就不能暴露set()方法
我们可以把校验逻辑放到builder中,先创建建造者,通过set设置建造者变量,然后再使用build()创建真正对象前进行校验,然后把ResourcePoolConfig构造函数设置为private
public class ResourcePoolConfig {
@Getter
private String name;
@Getter
private int maxTotal;
@Getter
private int maxIdle;
@Getter
private int minIdle;
private ResourcePoolConfig(Builder builder) {
this.name = builder.name;
this.maxTotal = builder.maxTotal;
this.maxIdle = builder.maxIdle;
this.minIdle = builder.minIdle;
}
@Accessors(chain = true)
public static class Builder {
private static final int DEFAULT_MAX_TOTAL = 8;
private static final int DEFAULT_MAX_IDLE = 0;
private static final int DEFAULT_MIN_IDLE = 0;
@Setter
private String name;
@Setter
private int maxTotal = DEFAULT_MAX_TOTAL;
@Setter
private int maxIdle = DEFAULT_MAX_IDLE;
@Setter
private int minIdle = DEFAULT_MIN_IDLE;
public ResourcePoolConfig build() {
//属性检验逻辑...
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException("...");
}
if (maxIdle > maxTotal) {
throw new IllegalArgumentException("...");
}
return new ResourcePoolConfig(this);
}
}
}
//使用
ResourcePoolConfig dbConfig = new Builder()
.setName("DBConfig")
.setMaxIdle(10)
.setMaxIdle(12)
.build();
使用建造者模式创建对象,还能避免对象存在无效状态问题
如果不适用建造者模式,先创建对象再set,会导致set第一个之后对象处于无效状态。为了避免这种状态存在,我们就需要一次性初始化好全部成员变量。如果构造函数参数过多我们就可以考虑建造者模式,但是使用建造者创建对象代码重复冗余。
与工厂模式区别
实际上,工厂模式是用来创建不同但是类型相关的对象(继承同一父类或者接口一组子类),由给定的参数来决定创建哪种类型对象。建造者是用来创建一种复杂对象,通过设置不同可选参数,‘定制化’建不同的对象。
实际上,我们最主要需要知道每个模式为什么这么设计,能解决什么问题,只有了解了这些最本质问题,才能不生搬硬套,才能灵活运用,甚至混用各种创造新模式,来解决特定问题。