What

通过构建者类来创建同一个类的不同参数的实例对象,起到校验参数、隔离变化的、对象存在无效状态等作用。这样的对象创建模式就是构建者模式。

  • 应用场景

如果一个类中有很多属性,为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合 set() 方法来解决。但是,如果存在下面情况中的任意一种,我们就要考虑使用建造者模式了:

  1. 我们把类的必填属性放到构造函数中,强制创建对象的时候就设置。如果必填的属性有很多,把这些必填属性都放到构造函数中设置,那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置,那校验这些必填属性是否已经填写的逻辑就无处安放了。
  2. 如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造函数配合 set() 方法的设计思路,那这些依赖关系或约束条件的校验逻辑就无处安放了。
  3. 如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。

    How

    ```java /**
    • 经典实现方式 */ public class ClassicWay { public static void main(String[] args) { // 这段代码会抛出IllegalArgumentException,因为minIdle>maxIdle ResourcePoolConfig config = new ResourcePoolConfig.Builder()
      1. .setName("dbconnectionpool")
      2. .setMaxTotal(16)
      3. .setMaxIdle(10)
      4. .setMinIdle(12)
      5. .build();
      } }

class ResourcePoolConfig { private String name; private int maxTotal; private int maxIdle; private int minIdle;

/**
 * 构造函数
 * 通过校验无误的Builder对象来初始化对象
 *
 * @param builder
 */
private ResourcePoolConfig(Builder builder) {
    this.name = builder.name;
    this.maxTotal = builder.maxTotal;
    this.maxIdle = builder.maxIdle;
    this.minIdle = builder.minIdle;
}
//...省略getter方法...

/**
 * 构建者类
 * <p>
 * 此处将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 ResourcePoolConfig build() {
        // 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等
        if (StrUtil.isBlank(name)) {
            throw new IllegalArgumentException("...");
        }
        if (maxIdle > maxTotal) {
            throw new IllegalArgumentException("...");
        }
        if (minIdle > maxTotal || minIdle > maxIdle) {
            throw new IllegalArgumentException("...");
        }
        //校验无误,创建目标对象
        return new ResourcePoolConfig(this);
    }

    public Builder setName(String name) {
        if (StrUtil.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;
    }
}

} ```