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

建造者模式

  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.hqwc.cn/news/297474.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud + Vue前后端分离-第7章 核心业务功能开发

Spring Cloud Vue前后端分离-第7章 核心业务功能开发 7-1 课程管理功能开发 课程管理页面美化 1.课程管理页面美化 demo-course.jpg 复制search.html中的部分代码 course.vue 看效果 测试一下新增修改删除效果 1.课程管理页面美化2 scoped:style下的样式只应用于当前组件…

BUG记录 | 使用阿里云OSS实现文件上传后,得到的url无法在浏览器中打开

项目背景 SpringBoot的项目,使用阿里云对象存储OSS对项目中的文件进行存储,所需文件也会通过IDEA中由官方Demo改编而成的工具类作为接口,调用接口后上传 问题描述 使用阿里云OSS实现文件上传后,通过postman测试得到的url无法在…

MyBatis动态sql中foreach标签介绍和使用

MyBatis动态sql中foreach标签介绍和使用 参数解释: foreach 的主要作用在构建 in 条件中,它可以在 sql 语句中进行迭代一个集合。foreach 元素的属性主要有 collection,item,separator,index,open&#x…

怎么做好数字化工厂的建设?

怎样建设好的数字化工厂,不但须要有充足的费用预算,更加需要科学研究的计划和设计方案,一般做好智能化基本建设,务必要根据下列流程: 一.信息管理系统的计划和设计方案   许多的工厂会购买许多的单独的信息管理系统&…

CreateProcess error=216, 该版本的 %1 与你运行的 Windows 版本不兼容。请查看计算机的系统信息,然后联系软件发布者。

第一个go程序就出错了,错误提示: Error running ‘go build hello.go’: Cannot run program “C:\Users\Administrator\AppData\Local\Temp___go_build_hello_go.exe” (in directory “G:\go\workspace”): CreateProcess error216, 该版本的 %1 与你运…

【面向对象】对比JavaScript、Go、Ada、Python、C++、Java、PHP的访问限制。

在不同编程语言中,控制成员(变量、方法、类等)可见性的机制不尽相同。以下是对比JavaScript、Go、Ada、Python、C、Java、PHP所使用的访问限制关键字和约定: 一、JavaScript ### JavaScript访问限制 早期的JavaScript并没有类似…

Python 运维(三):使用 zipapp 将 Python 程序打包成单个可执行文件

大家好,我是水滴~~ 在 Python 开发中,我们经常需要将应用程序打包成可执行文件,以便在不具备 Python 环境的计算机上运行。Python 提供了多种打包工具,其中之一就是 zipapp。zipapp 可以将 Python 应用程序及其依赖打包成一个单独…

Spring5底层原理之BeanFactory与ApplicationContext

目录 BeanFactory与ApplicationContext BeanFactory ApplicationContext 容器实现 BeanFactory实现 ApplicationContext实现 ClassPathXmlApplicationContext的实现 AnnotationConfigApplicationContext的实现 AnnotationConfigServletWebServerApplicationContext的实…

【项目管理】CMMI-需求跟踪矩阵模版

需求菜单/功能模块需求名称需求变更类型(新增、修改)需求状态(已建议、已批准、已设计、已实现、已验证、已删除)优先级(高、中、低)软件需求(工作产品、章节号)概要设计&#xff08…

听GPT 讲Rust源代码--src/tools(25)

File: rust/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs 在Rust源代码中,suspicious_command_arg_space.rs文件位于clippy_lints工具包的methods目录下,用于实现Clippy lint SUSPICIOUS_COMMAND_ARG_SPACE。 Clippy是Ru…

【计算机网络】网络层——IP协议

目录 一. 基本概念 二. 协议报文格式 三. 网段划分 1. 第一次划分 2. CIDR方案 3. 特殊的IP地址 四. IP地址不足 1. 私有IP和公网IP 2. DHCP协议 3. 路由器 4. NAT技术 内网穿透(NAT穿透) 五. 路由转发 路由表生成算法 结束语 一. 基本概念 IP指网络互连协议…

【C++】开源:FLTK图形界面库配置与使用

😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍FLTK图形界面库配置与使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下&#xff0…