设计模式 建造者模式 与 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实例的可以查看这个类的实现

相关推荐
程序员与背包客_CoderZ3 小时前
C++设计模式——Abstract Factory Pattern抽象工厂模式
c语言·开发语言·c++·设计模式·抽象工厂模式
zzzhpzhpzzz3 小时前
设计模式——组合实体模式
设计模式
zzzhpzhpzzz6 小时前
设计模式——前端控制器模式
设计模式
forestsea6 小时前
【Java 解释器模式】实现高扩展性的医学专家诊断规则引擎
java·人工智能·设计模式·解释器模式
小白不太白9509 小时前
设计模式之 命令模式
设计模式·命令模式
吃汉堡吃到饱9 小时前
【创建型设计模式】单例模式
单例模式·设计模式
小白不太白9509 小时前
设计模式之 备忘录模式
服务器·设计模式·备忘录模式
zzzhpzhpzzz9 小时前
设计模式——策略模式
设计模式·策略模式
入门到跑路9 小时前
【君正T31开发记录】8.了解rtsp协议及设计模式
网络协议·设计模式
小白不太白9509 小时前
设计模式之 解释器模式
java·设计模式·解释器模式