美文网首页
建造者模式

建造者模式

作者: lj72808up | 来源:发表于2021-04-13 11:38 被阅读0次

    一. 建造者模式的产生

    1. 现在, 我们需要定义一个资源池配置类 ResourcePoolConfig
      该类有三个属性 maxTotal、maxIdle、minIdle. 这3个参数本身有默认值 DEFAULT_MAX_TOTAL, DEFAULT_MAX_IDLE, DEFAULT_MIN_IDLE, 所以不是必填参数, 不需要在构造函数中初始化,应该放在 setter() 中配置. 根据上面的分析有如下代码:

      class ResourcePoolConfig {
          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(String name) {
              if (name.equals("")) {
                  throw new IllegalArgumentException("name should not be empty.");
              }
          }
      
          public void setMaxTotal(int maxTotal) {
              this.maxTotal = maxTotal;
          }
      
          public void setMaxIdle(int maxIdle) {
              this.maxIdle = maxIdle;
          }
      
          public void setMinIdle(int minIdle) {
              this.minIdle = minIdle;
          }
      }
      
    2. 如果 maxTotal、maxIdle、minIdle 这三个参数是相关联的, 只要设置其中一个, 就必须设置另外两个. 这种情况下, setter 函数必须连续调用, 否则会造成中间状态不可用. 且三个参数设置的值要校验为正数才有意义. 所以:

      • 我们可以把校验逻辑放置到 Builder 类中,先创建建造者,并且通过 set() 方法设置建造者的变量值,
      • 然后再使用 build() 方法真正创建对象之前,做集中的校验,校验通过之后才会创建对象。
      • 除此之外,我们把 ResourcePoolConfig 的构造函数改为 private 私有权限。这样我们就只能通过建造者来创建 ResourcePoolConfig 类对象。并且,ResourcePoolConfig 没有提供任何 set() 方法,这样我们创建出来的对象就是不可变对象了。
      public class ResourcePoolConfig {
          private String name;
          private int maxTotal;
          private int maxIdle;
          private int minIdle;
      
          private ResourcePoolConfig(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 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 ResourcePoolConfig(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;
              }
          }
      }
      

    二. 为什么使用建造者模式

    1. 直接使用构造函数或者配合 set 方法就能创建对象,为什么还需要建造者模式来创建呢?

    实际上,如果我们并不是很关心对象是否有短暂的无效状态,也不是太在意对象是否是可变的。比如,对象只是用来映射数据库读出来的数据,那我们直接暴露 set() 方法来设置类的成员变量值是完全没问题的。而且,使用建造者模式来构建对象,代码实际上是有点重复的,ResourcePoolConfig 类中的成员变量,要在 Builder 类中重新再定义一遍。

    2. 建造者模式和工厂模式都可以创建对象,那它们两个的区别在哪里呢?

    实际上,工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式是用来创建一种类型的复杂对象,通过设置不同的可选参数,“定制化”地创建不同的对象。

    相关文章

      网友评论

          本文标题:建造者模式

          本文链接:https://www.haomeiwen.com/subject/vkwqlltx.html