设计模式 建造者模式 与 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.mzph.cn/news/370521.shtml

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

相关文章

java 布隆过滤器_什么是布隆过滤器(Bloom Filter)?

在日常工作中,有一个比较常见的需求,就是需要判断一个元素是否在集合中。例如以下场景:给定一个IP黑名单库,检查指定IP是否在黑名单中?在接收邮件的时候,判断一个邮箱地址是否为垃圾邮件?在文字…

STM32上使用JSON

一、STM32工程中添加JSON 最近在一网2串项目,串口和网口之间可能需要定义一下简单的通信协议,而通信协议上则需要去定义一下通信的数据格式,上次听剑锋说要用Json来定义,目前查了下资料具体如何去应用还不 会。因为最新的KEIL上支…

Flex 学习

Flex案例一&#xff1a; 1 <html>2 <head>3 <meta http-equiv"Content-Type" content"text/html; charsetutf-8" /> 4 <title>无标题</title>5 <style type"text/css">6 body,h1,h2,h3,h4,…

Cocos2d-X中实现自己定义菜单处理事件

当用户点击再松开后才会响应菜单事件&#xff0c;而在游戏中有些游戏须要玩家点击后就处理事件。如玩坦克大战的时候&#xff0c;玩家是点击一下就发射子弹。并是点击松手后发射子弹&#xff0c;在Cocos2d-X中没有这样的消息。以下就通过自己定义的方式实现当用户点击后就调用处…

java linkedhashset_java之LinkedHashSet

LinkedHashSet是Set集合的一个实现&#xff0c;具有set集合不重复的特点&#xff0c;同时具有可预测的迭代顺序&#xff0c;也就是我们插入的顺序。并且linkedHashSet是一个非线程安全的集合。如果有多个线程同时访问当前linkedhashset集合容器&#xff0c;并且有一个线程对当前…

Jmeter 场景设计

今天的业务场景是&#xff1a; 1.管理员登录后台---登录成功后添加一个某类型的产品---产品添加成功后&#xff0c;再为该产品添加10个排期。 2.管理员登录后台--登录成功后添加多个不同类型产品---产品全部添加完成后&#xff0c;依次为所有产品添加10个排期。 这是两种不同的…

Android IPC机制(五)用Socket实现跨进程聊天程序

1.Socket简介 Socket也称作“套接字“&#xff0c;是在应用层和传输层之间的一个抽象层&#xff0c;它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。它分为流式套接字和数据包套接字&#xff0c;分别对应网络传输控制层的TCP和UDP协议。TCP协…

java获取byte 长度_java获取字节的长度.

我们经常要获取中文,数字,或者英文字符所占字节的长度,下面就列出各种编码格式下所占字节的长度:代码如下:package pack.java.midea.dao;import java.io.UnsupportedEncodingException;/*** 测试;* author zhouhaitao* 2012-5-17*/public class Test {/*** param args* throws …

Batoo JPA –比领先的JPA提供商快15倍

介绍 我早在2000年代就喜欢JPA 1.0。 我甚至在稳定版本发布之前就将其与EJB 3.0一起使用。 我非常喜欢它&#xff0c;因此我为JBoss 3.x实现贡献了一些零碎的部分。 那时我们公司规模还很小。 创建新功能和应用程序比性能更重要&#xff0c;因为我们有很多想法&#xff0c;我…

python软件是哪个国家的品牌_有哪些好用的软件被国人误认为是外国研发的?

国产软件被标榜上了英文&#xff0c;即便不是英文&#xff0c;用拼音写出来&#xff0c;也会有人误认为是国外的软件。因为这样可以显得高大上&#xff0c;为什么我们会有这样的想法&#xff0c;是崇洋媚外吗&#xff0c;并不是&#xff0c;而是之前的国产软件的确有不少让我们…

postgres 支持的线程数_线程池被打满了怎么处理呢,你是否真的了解线程池?

0、前言线程池&#xff0c;顾名思义就是线程的池子&#xff0c;在每次需要取线程去执行任务的时候&#xff0c;没必要每次都创建新线程执行&#xff0c;线程池就是起着维护线程的作用&#xff0c;当有任务的时候就取出一个线程执行&#xff0c;如果任务执行完成则把线程放回到池…

[树形DP]没有上司的舞会

题目链接 思考 首先本题中的关系是一种树形结构&#xff0c;而且符号最优子结构和无后效性&#xff0c;所以可以进行记忆化搜索。 那么首先要在这颗树中选出一个点作为根节点&#xff0c;按照习惯我们将没有父节点的点作为根节点。 接下来要思考的是 状态&#xff1a; dp[i][0…

mybatis通用mapper_全网最全Mapper解析,附实操代码帮你更好理解

今天给大家介绍一位老朋友当你第一次接触Java开发的时候&#xff0c;这个老朋友就和你形影不离&#xff0c;当你要进行ORM的时候&#xff0c;单表的增删改查&#xff0c;这位老朋友给了你极大的帮助&#xff0c;不知道你想到他了吗&#xff1f;对&#xff0c;这就是通用mapper&…

初尝微信小程序2-基本框架

基本框架&#xff1a; .wxml &#xff1a;页面骨架 .wxss &#xff1a;页面样式 .js &#xff1a;页面逻辑 描述一些行为 .json &#xff1a;页面配置 创建一个小程序之后&#xff0c;app.js,app.json,app.wxss是必须的&#xff0c;而且名字也不能随意更改&#xff0c;…

洛谷 P1795 无穷的序列_NOI导刊2010提高(05)

P1795 无穷的序列_NOI导刊2010提高&#xff08;05&#xff09; 题目描述 有一个无穷序列如下&#xff1a; 110100100010000100000… 请你找出这个无穷序列中指定位置上的数字 输入输出格式 输入格式&#xff1a;第一行一个正整数N&#xff0c;表示询问次数&#xff1b; 接下来的…

此服务器的时钟与主域控制器的时钟不一致_中移动“超高精度时间同步服务器”开标,两家中标...

8月25日&#xff0c;中国移动发布《2020年至2022年同步网设备集中采购_中标候选人公示》公告。两家中标。同步网技术比较小众&#xff0c;但是同步网是5G承载网的重要一环&#xff0c;分享一下&#xff0c;供大家参考。中标情况 标包1-时钟同步设备中标候选人依次排序为&#x…

java 异常管理员_GitHub - kangZan/JCatch: Exception异常管理平台,支持Java、PHP、Python等多种语言...

什么是JCatch当程序发生异常(Exception)&#xff0c;处理方式一般是通过日志文件记录下来&#xff0c;这种方式很容易被忽略&#xff0c;而且查询起来比较麻烦。JCatch提供了一种方案&#xff0c;当程序发生异常时&#xff0c;通过JCatch平台接口提交到JCatch平台&#xff0c;由…

oled

gnd、vcc、clk、miso、rst、mosi、cs 转载于:https://www.cnblogs.com/scrazy/p/7892733.html

使用html css js实现计算器

使用html css js实现计算器&#xff0c;开启你的计算之旅吧 效果图&#xff1a; 代码如下&#xff0c;复制即可使用&#xff1a; <!DOCTYPE html><html lang"en"> <head> <meta charset"utf-8"> <style> /* 主体 */ .co…

面向对象的三个基本特征

面向对象的三个基本特征是&#xff1a;封装、继承、多态。封装 封装最好理解了。封装是面向对象的特征之一&#xff0c;是对象和类概念的主要特性。封装&#xff0c;也就是把客观事物封装成抽象的类&#xff0c;并且类可以把自己的数据和方法只让可信的类或者对象操作&#xff…