构造器赋值,适合参数少时,参数一多可能出现如下问题:
解决构造器赋值的最简单的方式就是用setter函数来给成员变量赋值,以替代冗长的构造函数。
使用setter时依旧可能存在不足之处:
为了解决上面的问题,可以使用建造者模式。
Builder 模式,中文翻译为建造者模式或者构建者模式,也有人叫它生成器模式。
相关文章 Java设计模式学习笔记—建造者模式
public class ResourcePoolConfig3 {
private String name;
private int maxTotal;
private int maxIdle;
private int minIdle;
private ResourcePoolConfig3(Builder builder) {
this.name = builder.name;
this.maxTotal = builder.maxTotal;
this.maxIdle = builder.maxIdle;
this.minIdle = builder.minIdle;
}
//...省略getter方法...
// 将Builder类设计成了ResourcePoolConfig的内部类。
// 也可以将Builder类设计成独立的非内部类ResourcePoolConfigBuilder。
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 ResourcePoolConfig3 build() {
// 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException("...");
}
if (maxIdle > maxTotal) {
throw new IllegalArgumentException("...");
}
if (minIdle > maxTotal || minIdle > maxIdle) {
throw new IllegalArgumentException("...");
}
return new ResourcePoolConfig3(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;
}
}
public static void main(String[] args) {
// 这段代码会抛出IllegalArgumentException,因为minIdle>maxIdle
ResourcePoolConfig3 config = new ResourcePoolConfig3.Builder()
.setName("dbconnectionpool")
.setMaxTotal(16)
.setMaxIdle(10)
.setMinIdle(12)
.build();
}
}
若用setter方式创建一个长方形,在使用第一个setter创建高度(或宽度)时,尚未设置另一个属性,此时便处于无效状态。
Rectangle r = new Rectange(); // r is invalid
r.setWidth(2); // r is invalid
r.setHeight(3); // r is valid
若并不是很关心对象是否有短暂的无效状态,也不是太在意对象是否是可变的,直接暴露 set() 方法来设置类的成员变量值是完全没问题的。
使用建造者模式来构建对象,代码实际上是有点重复的,ResourcePoolConfig 类中的成员变量,要在 Builder 类中重新再定义一遍。
建造者模式是让建造者类来负责对象的创建工作,工厂模式是由工厂类来负责对象创建的工作。
该部分来自《Head First设计模式》,有的地方可能过于抽象或官方语言,仅作相关参考。