设计模式-建造者模式

建造者模式


文章目录

  • 建造者模式
  • 什么是建造者模式
  • 为什么要用建造者模式
  • 如何实现建造者模式
  • 与工厂模式有何区别
  • 建造者模式有何缺陷
  • 总结


什么是建造者模式

  建造模式(Builder Pattern)是对象的创建模式。它可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
  简单理解的话就是不再使用简单的new关键字创建对象,然后使用setXxx的方式设置属性,而是将对象的创建和属性的设置相关联。


为什么要用建造者模式

  当一个类的属性非常多,有的必填有的非必填,且有的属性之间有依赖关系。此时,单纯的使用new关键字和setXxx的话,不能优雅的拆创建对象,就比较适合使用建造者。举个例子:
  我们需要定义连接池类 ConnectPool。属性值列表如下

属性名称 中文释义 是否必填 默认值
name 名称
maxConnect 最大连接数 8
minConnect 最小连接数 1

那么我们在创建这个ConnectPool类对象的时候,在使用建造者之前我们的构造函数是这样的:

public class ConnectPool{
  private static final int DEFAULT_MAX = 8;
  private static final int DEFAULT_MIN = 1;

  private String name;
  private int maxConnect= DEFAULT_MAX;
  private int minConnect= DEFAULT_MIN;

  public ConnectPool(String name, Integer maxConnect, Integer minConnect) {
    if (StringUtils.isBlank(name)) {
      throw new IllegalArgumentException("name should not be empty.");
    }
    this.name = name;

    if (maxConnect!= null) {
      if (maxConnect<= 1) {
        throw new IllegalArgumentException("maxConnect should be positive.");
      }
      this.maxConnect= maxConnect;
    }

    if (minConnect!= null) {
      if (minConnect< 1) {
        throw new IllegalArgumentException("maxConnect should not be negative.");
      }
      this.minConnect= minConnect;
    }
  }
  //...省略getter方法...
}

  现在只有3个属性,我们的构造函数就已经非常臃肿了,那么怎么解决构造函数臃肿的问题呢,你可能想到使用set属性值的方式,那么属性值的校验就必须放在构造函数外面,显然这是一个不可把控的风险(你不能确保后面使用这个类的同事在构造的时候进行校验)。
  此时其实建造者模式就可以排上用场了,我们可以把校验逻辑放置到 Builder 类中,先创建建造者,并且通过 set() 方法设置建造者的变量值,然后在使用 build() 方法真正创建对象之前,做集中的校验,校验通过之后才会创建对象。除此之外,我们把 ConnectPool的构造函数改为 private 私有权限。这样我们就只能通过建造者来创建 ConnectPool类对象。并且,ConnectPool没有提供任何 set() 方法,这样我们创建出来的对象就是不可变对象了。


如何实现建造者模式

  建造者模式一般都以Builder结尾,我们直接代码示例:

public class ConnectPool{
  private String name;
  private int maxConnect;
  private int minConnect;
  
  private ConnectPool(Builder builder) {
    this.name = builder.name;
    this.maxConnect= builder.maxConnect;
    this.minConnect= builder.minConnect;
  }
  //...省略getter方法...

  //我们将Builder类设计成了ConnectPool的内部类。
  //我们也可以将Builder类设计成独立的非内部类ConnectPoolBuilder。
  public static class Builder {
  	private static final int DEFAULT_MAX = 8;
  	private static final int DEFAULT_MIN = 1;
  
    private String name;
  	private int maxConnect= DEFAULT_MAX;
  	private int minConnect= DEFAULT_MIN;
  	
    public ConnectPoolbuild() {
      // 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等
      if (StringUtils.isBlank(name)) {
        throw new IllegalArgumentException("...");
      }
      if (minConnect> maxConnect) {
        throw new IllegalArgumentException("...");
      }

      return new ConnectPool(this);
    }

    public Builder setName(String name) {
      if (StringUtils.isBlank(name)) {
        throw new IllegalArgumentException("...");
      }
      this.name = name;
      return this;
    }

    public Builder setMaxConnect(int maxConnect) {
      if (maxConnect<= 1) {
        throw new IllegalArgumentException("...");
      }
      this.maxConnect= maxConnect;
      return this;
    }

    public Builder setMinConnect(int minConnect) {
      if (minConnect< 1) {
        throw new IllegalArgumentException("...");
      }
      this.minConnect= minConnect;
      return this;
    }
  }
}

// 这段代码会抛出IllegalArgumentException,因为minIdle>maxIdle
ConnectPoolconfig = new ConnectPool.Builder()
        .setName("dbconnectionpool")
        .setMaxConnect(16)
        .setMinConnect(10)
        .build();


与工厂模式有何区别

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

建造者模式有何缺陷

  建造者模式来构建对象, 类中的成员变量,要在 Builder 类中重新再定义一遍,会使代码略显重复。


总结

  何时使用建造者模式我们可以这样来判别:

  • 1.需要生成的产品对象有复杂的内部结构。
  • 2.需要生成的产品对象的属性相互依赖。
  • 3.在对象创建过程中会使用到系统中的其他一些对象,这些对象在产品对象的创建过程中不易得到。

你可能感兴趣的:(设计模式,设计模式,建造者模式,java)