建造者设计模式(Builder Design Pattern)

81 阅读2分钟

参考资料

image.png

应用场景

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

建造者模式实现方式

场景:

  • name是必需字段
  • 配置项直接有依赖关系:
    • 如果设置了 maxTotal、maxIdle、minIdle 其中一个,就必须显式地设置另外两个
    • maxIdle 和 minIdle 要小于等于 maxTotal。
  • ResourcePool是不可变对象,创建后不可再通过setter方法修改属性
public class ResourcePool{
	private String name;
	private int maxTotal;
	private int maxIdle;
	private int minIdle;

	private ResourcePool(Builder builder){
		this.name = builder.name;
		this.maxTotal = builder.maxTotal;
		this.maxIdle = builder.maxIdle;
		this.minIdle = builder.minIdle;
	}
	//省略getter方法
	//不要setter方法

	//这里将Builder类设计成了ResourcePool的内部类。 
	//也可以将Builder类设计成独立的非内部类ResourcePoolBuilder。
	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 ResourcePool(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; 
		} 
	}
}

建造者模式还可以避免对象短暂的无效状态。


与工厂模式的区别

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