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

news/2025/1/15 18:02:54/

建造者模式

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

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

  1. 产品(Product): 要创建的产品类对象
  2. 抽象建造者(Builder): 建造者的抽象类, 一般用来定义建造细节的方法, 并不涉及具体的对象部件的创建
  3. 具体建造者(ConcreteBuilder): 具体的Builder类, 根据不同的业务逻辑, 实现对象的各个组成部分的创建
  4. 调度者(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实例的可以查看这个类的实现


http://www.ppmy.cn/news/1281618.html

相关文章

http和https、http状态码分类

http协议是hyper text transfer protocol的缩写。 https是加了ssl外壳的http。https是一种通过计算机网络进行安全通信的传输协议,经由http进行通信,利用SSL/TLS建立全信道,加密数据包。https使用的主要目的是提供对网站服务器的身份认证&am…

C++中的存储类及其实例

文章目录 0. 语法1. 自动存储类自动存储类对象的属性自动存储类的例子 2. 外部存储类extern存储类对象的属性extern存储类的例子 3. 静态存储类静态存储类的属性静态存储类的例子 4. 寄存器存储类寄存器存储类对象的属性寄存器存储类例子 5. 可变(mutable&#xff0…

Android 手机对于Arduino蓝牙控制解决方案

1、Android系统概述 ​ Android 系统是 Google 公司基于 Linux 内核开发的移动端操作系统,适用于智能手机智能手表平板电脑等设备,最新的版本为 7.1。Android系统具有免费开源的优势,任何企业与个人都可以查阅公开的 API 文档,并在自己开发的应用中通过调…

iOS使用CXCallObserver监听电话接听与拨打

初始化 import CallKitclass HomeViewController: UIViewController, CXCallObserverDelegate {public var cacheManager: TripCacheManager TripCacheManager.init()override func viewDidLoad() {super.viewDidLoad()self.callObserver.setDelegate(self, queue: DispatchQ…

如何处理uni-app中的跨平台差异

在uni-app中,可以通过条件编译和平台判断来处理跨平台差异代码。具体步骤如下: 在uni-app项目的根目录下,找到名为manifest.json的文件,这是uni-app的配置文件。 在manifest.json文件中,可以使用条件编译指令来处理不…

SperingBoot+vue文件上传下载预览

上传文件: 前端: 整个过程,就是在使用FormData 添加 上File(这个Blob),并且key要和后台的名字对应上在点击上传按钮开始上传之前,使用了URL.createObjectURL(File)创建blobUrl,给了…

树莓派Pi4B简介

树莓派是什么?Raspberry Pi(中文名为“树莓派”,简写为RPi,或者RasPi/RPi)是为学生计算机编程教育而设计,只有信用卡大小的卡片式电脑,其系统基于Linux。 树莓派4B与树莓派3B/3B参数对比: 具体的实物图如下&#xff1a…

前端框架前置学习(4) AJAX

同步代码和异步代码 同步代码 浏览器按照我们书写代码的顺序一行一行地执行程序.浏览器会等待代码的解析和工作,在上一行代码完成之后才会执行下一行代码.这被称之为同步程序 逐行执行,需要原地等待结果 异步代码 异步编码技术使得程序可以在执行一个可能长期运行的任务的…