建造者模式
- 定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
- 主要作用: 在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象
- 如何使用: 用户只需要给出指定复杂对象的类型和内容, 建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
- 解决的问题:
- 方便用户创建复杂的对象 不需要知道实现过程
- 代码复用性/封装性 将对象构建过程和细节进行封装/复用
- 注意事项: 与工厂模式的区别 建造者模式更加关注与零件装配的顺序, 一般用来创建更为复杂的对象
建造者一般有如下四个角色
- 产品
(Product)
: 要创建的产品类对象 - 抽象建造者
(Builder)
: 建造者的抽象类, 一般用来定义建造细节的方法, 并不涉及具体的对象部件的创建 - 具体建造者
(ConcreteBuilder)
: 具体的Builder类, 根据不同的业务逻辑, 实现对象的各个组成部分的创建 - 调度者
(Director)
: 调用具体建造者来创建复杂产品(Product)
的各个部分, 并按照一定顺序或流程, 来建造复杂对象
简单实现建造者模式
产品
(Product)
/**
* @author LionLi
*/
public class Product {
private Long id;
private String name;
private String number;
private Integer type;
private String description;
// ----- get set -----
}
建造者
(ProductBuilder)
将复杂的构建过程封装起来, 这里如果有多种产品的建造者可以抽象出一个抽象建造者
将实现交给不同产品的具体建造者子类
/**
* @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;
}
}
测试类
/**
* @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
代码
/**
* 链式建造者
*
* @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;
}
}
测试类
/**
* @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
注解, 只需要增加一个注解即可完成建造者模式是不是非常的简单
/**
* @author LionLi
*/
@Data
@Builder
public class Product {
private Long id;
private String name;
private String number;
private Integer type;
private String description;
}
测试类
/**
* @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的构建过程还是很复杂的每个方法都做了很多操作
/**
* 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实例的可以查看这个类的实现