设计模式 建造者模式 与 Spring Bean建造者 BeanDefinitionBuilder 源码与应用

建造者模式

  1. 定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
  2. 主要作用: 在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象
  3. 如何使用: 用户只需要给出指定复杂对象的类型和内容, 建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
  4. 解决的问题:
  • 方便用户创建复杂的对象 不需要知道实现过程
  • 代码复用性/封装性 将对象构建过程和细节进行封装/复用
  1. 注意事项: 与工厂模式的区别 建造者模式更加关注与零件装配的顺序, 一般用来创建更为复杂的对象

建造者一般有如下四个角色

  1. 产品(Product): 要创建的产品类对象
  2. 抽象建造者(Builder): 建造者的抽象类, 一般用来定义建造细节的方法, 并不涉及具体的对象部件的创建
  3. 具体建造者(ConcreteBuilder): 具体的Builder类, 根据不同的业务逻辑, 实现对象的各个组成部分的创建
  4. 调度者(Director): 调用具体建造者来创建复杂产品(Product)的各个部分, 并按照一定顺序或流程, 来建造复杂对象

简单实现建造者模式

产品(Product)

java 复制代码
/**
 * @author LionLi
 */
public class Product {

    private Long id;
    private String name;
    private String number;
    private Integer type;
    private String description;
    
    // ----- get set -----
}

建造者(ProductBuilder)将复杂的构建过程封装起来, 这里如果有多种产品的建造者可以抽象出一个抽象建造者将实现交给不同产品的具体建造者子类

java 复制代码
/**
 * @author LionLi
 */
public class ProductBuilder {

    private final Product product = new Product();
    
    public void id(Long id) {
        product.setId(id);
    }
    public void name(String name) {
        product.setName(name);
    }
    public void number(String number) {
        product.setNumber(number);
    }
    public void type(Integer type) {
        product.setType(type);
    }
    public void description(String description) {
        product.setDescription(description);
    }
    public Product build() {
        return product;
    }
}

测试类

java 复制代码
/**
 * @author LionLi
 */
public class Test {
    public static void main(String[] args) {
        ProductBuilder builder = new ProductBuilder();
        builder.id(1L);
        builder.name("666");
        builder.number("CP123");
        builder.type(1);
        builder.description("测试");
        System.out.println(builder.build());
    }
}

链式建造者写法

在平常的应用中, 建造者模式通常是采用链式编程的方式构建对象, 修改ProductBuilder代码

java 复制代码
/**
 * 链式建造者
 *
 * @author LionLi
 */
public class ProductBuilder {

    private final Product product = new Product();

    public ProductBuilder id(Long id) {
        product.setId(id);
        return this;
    }
    public ProductBuilder name(String name) {
        product.setName(name);
        return this;
    }
    public ProductBuilder number(String number) {
        product.setNumber(number);
        return this;
    }
    public ProductBuilder type(Integer type) {
        product.setType(type);
        return this;
    }
    public ProductBuilder description(String description) {
        product.setDescription(description);
        return this;
    }
    public Product build() {
        return product;
    }
}

测试类

java 复制代码
/**
 * @author LionLi
 */
public class Test {
    public static void main(String[] args) {
        ProductBuilder builder = new ProductBuilder();
        Product product = builder.id(1L).name("666")
            .number("CP123").type(1)
            .description("测试链式").build();
        System.out.println(product);
    }
}

Lombok @Builder 注解实现建造者模式

我们项目中最常使用的 Lombok 工具是如何实现的建造者呢, 我们来看一下

改造产品类适用 @Builder 注解, 只需要增加一个注解即可完成建造者模式是不是非常的简单

java 复制代码
/**
 * @author LionLi
 */
@Data
@Builder
public class Product {
    private Long id;
    private String name;
    private String number;
    private Integer type;
    private String description;
}

测试类

java 复制代码
/**
 * @author LionLi
 */
public class Test {
    public static void main(String[] args) {
        Product.ProductBuilder builder = Product.builder();
        Product product = builder.id(1L).name("666")
            .number("CP123").type(1)
            .description("测试链式").build();
        System.out.println(product);
    }
}

我们来看一下 Lombok 是如何实现的建造者模式

进入代码目录下的target目录找到class下的编译后的Product

首先是Product本身

然后是建造者ProductBuilder


可以看出跟我们上面写的几乎是相同的

Spring中建造者模式的应用

Spring框架中的建造者模式的应用有很多, 例如BeanDefinitionBuilder用于构建Bean定义信息对象, 将BeanDefinition的创建过程进行封装, 并提供BeanDefinitionBuilder各种Bean定义信息对象的创建方法, 其实现更加的简洁并且符合实际开发需求.

大家可以搜索找到 BeanDefinitionBuilder 类查看实现

BeanDefinitionBuilder 代码, 可以看出bean的构建过程还是很复杂的每个方法都做了很多操作

java 复制代码
/**
 * Programmatic means of constructing
 * {@link org.springframework.beans.factory.config.BeanDefinition BeanDefinitions}
 * using the builder pattern. Intended primarily for use when implementing Spring 2.0
 * {@link org.springframework.beans.factory.xml.NamespaceHandler NamespaceHandlers}.
 *
 * @author Rod Johnson
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @since 2.0
 */
public final class BeanDefinitionBuilder {

	/**
	 * Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}.
	 */
	public static BeanDefinitionBuilder genericBeanDefinition() {
		return new BeanDefinitionBuilder(new GenericBeanDefinition());
	}

	/**
	 * Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}.
	 * @param beanClassName the class name for the bean that the definition is being created for
	 */
	public static BeanDefinitionBuilder genericBeanDefinition(String beanClassName) {
		BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
		builder.beanDefinition.setBeanClassName(beanClassName);
		return builder;
	}

// ----- 太多了省略部分代码 -----


	/**
	 * The {@code BeanDefinition} instance we are creating.
	 */
	private final AbstractBeanDefinition beanDefinition;

	/**
	 * Our current position with respect to constructor args.
	 */
	private int constructorArgIndex;


	/**
	 * Enforce the use of factory methods.
	 */
	private BeanDefinitionBuilder(AbstractBeanDefinition beanDefinition) {
		this.beanDefinition = beanDefinition;
	}

	/**
	 * Return the current BeanDefinition object in its raw (unvalidated) form.
	 * @see #getBeanDefinition()
	 */
	public AbstractBeanDefinition getRawBeanDefinition() {
		return this.beanDefinition;
	}

	/**
	 * Validate and return the created BeanDefinition object.
	 */
	public AbstractBeanDefinition getBeanDefinition() {
		this.beanDefinition.validate();
		return this.beanDefinition;
	}

	/**
	 * Set the name of a static factory method to use for this definition,
	 * to be called on this bean's class.
	 */
	public BeanDefinitionBuilder setFactoryMethod(String factoryMethod) {
		this.beanDefinition.setFactoryMethodName(factoryMethod);
		return this;
	}

	/**
	 * Add an indexed constructor arg value. The current index is tracked internally
	 * and all additions are at the present point.
	 */
	public BeanDefinitionBuilder addConstructorArgValue(@Nullable Object value) {
		this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(
				this.constructorArgIndex++, value);
		return this;
	}

	/**
	 * Add a reference to a named bean as a constructor arg.
	 * @see #addConstructorArgValue(Object)
	 */
	public BeanDefinitionBuilder addConstructorArgReference(String beanName) {
		this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(
				this.constructorArgIndex++, new RuntimeBeanReference(beanName));
		return this;
	}

// ----- 太多了省略部分代码 -----

	/**
	 * Append the specified bean name to the list of beans that this definition
	 * depends on.
	 */
	public BeanDefinitionBuilder addDependsOn(String beanName) {
		if (this.beanDefinition.getDependsOn() == null) {
			this.beanDefinition.setDependsOn(beanName);
		}
		else {
			String[] added = ObjectUtils.addObjectToArray(this.beanDefinition.getDependsOn(), beanName);
			this.beanDefinition.setDependsOn(added);
		}
		return this;
	}

	/**
	 * Set whether this bean is a primary autowire candidate.
	 * @since 5.1.11
	 */
	public BeanDefinitionBuilder setPrimary(boolean primary) {
		this.beanDefinition.setPrimary(primary);
		return this;
	}

	/**
	 * Apply the given customizers to the underlying bean definition.
	 * @since 5.0
	 */
	public BeanDefinitionBuilder applyCustomizers(BeanDefinitionCustomizer... customizers) {
		for (BeanDefinitionCustomizer customizer : customizers) {
			customizer.customize(this.beanDefinition);
		}
		return this;
	}

}

BeanDefinitionBuilder的应用

大家可以搜索找到 AbstractSingleBeanDefinitionParser 类查看实现

AbstractSingleBeanDefinitionParser 是一个解析并生成单例Bean对象的解析器, BeanDefinitionBuilder具体如何创建Bean实例的可以查看这个类的实现

相关推荐
ADRU24 分钟前
设计模式-责任链模式
java·设计模式·责任链模式
我是苏苏4 小时前
设计模式01:创建型设计模式之单例、简单工厂的使用情景及其基础Demo
java·开发语言·设计模式
帅到爆的努力小陈4 小时前
面向对象的设计原则与设计模式
设计模式
肘击鸣的百k路7 小时前
java设计模式
设计模式
bandaoyu7 小时前
【设计模式】命令模式
设计模式·命令模式
whynogome7 小时前
快速理解24种设计模式
设计模式
码农爱java8 小时前
设计模式--装饰器模式【结构型模式】
java·设计模式·面试·装饰器模式·原理·23 中设计模式
爱学习的白杨树8 小时前
设计模式介绍
设计模式
游客5208 小时前
设计模式-创建型-工厂方法模式
开发语言·python·设计模式·工厂方法模式
silver6878 小时前
工厂方法模式详解
设计模式