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

news2024/11/24 17:50:15

建造者模式

  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.coloradmin.cn/o/1333050.html

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

相关文章

软件测试工程师简历项目经验怎么写?--9999个已成功入职的软件测试工程师真实简历

简历是我们求职的第一步,也是非常重要的一步。 青云叔叔看过太多简历,最快3秒就淘汰一份简历,因为其实我们每天要收到很多简历进行筛选,那么面试官其实也是会很快进行对简历进行判断的,如果你对简历写的一塌糊涂&…

教师未来前景发展

教师是一个光荣而重要的职业,他们承担着培养下一代的责任和使命。随着社会的不断发展和变化,教师的前景也在不断扩大和改变。本文将探讨教师未来的前景发展,并提供一些思考和建议。 首先,教师的就业前景将继续扩大。随着人口的增长…

基于Kettle和帆软Finereport的血缘解析

一、背景: 用户经常会针对数据存在质量的存疑,反馈数据不准。开发人员排查数据质量问题步骤:首先和业务人员对接了解是哪里数据不准确,要定位是哪张报表,然后查看报表后面数据来源,然后一路排查数仓。往往定…

膛目结舌的代码技巧!一看就是冷暴力~~~~

你见过哪些令你膛目结舌的代码技巧? 代码世界有很多令人大呼小叫的技巧!有的代码像魔术师一样巧妙地隐藏了自己,有的像魔法师一样让你眼花缭乱,还有的像瑜伽大师一样灵活自如。它们让我们惊叹不已,让我们觉得自己仿佛置…

Axios 中的文件上传 File对象的方法

使用 FormData 对象 FormData是一个用于创建表单数据的 API,可用于发送包含文件和其他表单数据的multipart/form-data请求。这是处理文件上传的常用方法。通过FormData对象,可以将文件数据添加到表单中,然后使用 Axios 的post或put方法发送请求 在.env.development 文件中配…

分布式事务TCC补偿机制

文章目录 概述工作流程优缺点优点:缺点: 总结Java 示例代码 概述 TCC(Try-Confirm-Cancel)补偿机制是一种事务处理模式,用于确保分布式系统中的操作成功完成或在失败时进行补偿。TCC将一个事务拆分为三个阶段&#xf…

零基础快速上手HarmonyOS ArkTS开发2---ArkTS开发实践

ArkTS开发实践: 接着上一次零基础快速上手HarmonyOS ArkTS开发1---运行Hello World、ArkTS开发语言介绍继续, 在上一次对于ArkTS的基础知识进行了学习,依照官方的课程计划,还有两个具体的小案例需要来实践实践: 实践出…

基于Go语言的HTTP路由设计与实现

在Go语言的世界里,HTTP路由是一种将HTTP请求映射到相应处理函数的技术。通过路由,我们可以确定当用户发送一个HTTP请求时,应该调用哪个函数来处理该请求。在这个过程中,我们可以使用多种方法来实现路由设计,下面我将以…

leetcode——背包问题汇总

本章来汇总一下leetcode中做过的背包问题,包括0-1背包和完全背包。 背包问题的通常形式为:有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。求解将哪些物品装入背包里物品价值总和最大。0-1背包和…

040、全卷积

之——FCN 目录 之——FCN 杂谈 正文 1.FCN 2.实现 杂谈 FCN(Fully Convolutional Network)是一种深度学习网络架构,专门设计用于语义分割任务。传统的深度学习网络如卷积神经网络(CNN)在处理图像时通常用于分类…

学生管理系统 数据库版结果 查询student表中所有学生信息

1.创建school_java数据库 CREATE DATABASE schooljava; USE schooljava; CREATE TABLE student ( id INT(11), name VARCHAR(25), tel INT(11), sex VARCHAR(6) ); DESC student; java代码 package Mysql; import java.sql.Connection; import java.sql.DriverManager; imp…

16-高并发-队列术

队列,在数据结构中是一种线性表,从一端插入数据,然后从另一端删除数据。 在我们的系统中,不是所有的处理都必须实时处理,不是所有的请求都必须实时反馈结果给用户,不是所有的请求都必须100%一次性处理成功…

ubuntu下docker安装,配置python运行环境

参考自: 1.最详细ubuntu安装docker教程 2.使用docker搭建python环境 首先假设已经安装了docker,卸载原来的docker 在命令行中运行: sudo apt-get updatesudo apt-get remove docker docker-engine docker.io containerd runc 安装docker依赖 apt-get…

041、基于CNN的样式迁移

之——基于CNN的滤镜 目录 之——基于CNN的滤镜 杂谈 正文 1.基于CNN的样式迁移 2.实现 杂谈 通过CNN的特征提取,可以实现将一个图片的样式模式特征迁移到另一张图像上。 正文 1.基于CNN的样式迁移 就是在某些层的输出上用其他的图片进行监督。 2.实现 一般来…

算法基础之完全背包问题

完全背包问题 核心思想:集合表示: f[i][j]表示前i种物品 总容量不超过j的最大价值 求f[i][j]时 分为选0、1、2……n个第i种物品 n种情况 每种情况为 f[i][j-kv] (取k个第i种物品) 即f[i][j] max(f[i-1][j] , f[i-1][j-v]w,f[i-1][j-2v]2w….f[i-1][j-k…

探索应用程序的指路明灯:Route 和 Router 入门指南(上)

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

[MySQL binlog实战] 增量同步与数据搜索~从入门到精通

学习基础知识,并落实到实际场景(增量同步数据搜索) 对基础知识不感兴趣的,可以直接跳到应用场景 文章目录 binlog是什么简介产生方式文件格式statementrowmixed 怎么办开启 binlog查看 binlog其他查看相关命令运维查看 binlog设置…

ARM学习(24)Can的高阶认识和错误处理

笔者来聊一下CAN协议帧的认识和错误处理。 1、CAN协议帧认识 CAN 差分信号,是经过CAN收发器转成差分信号的,CAN RX和TX是逻辑电平。CAN的基础知识,可参考笔者这边文章:ARM学习(21)STM32 外设Can的认识与驱…

数据结构 | 查漏补缺

目录 数据的基本单位 冒泡排序 DFS和BFS中文 Prim 比较 中序线索二叉树 顺序栈 链栈 时间复杂度 循环队列 求第K个结点的值 数据的基本单位 数据元素 循环队列sq中,用数组elem[0‥25]存放数据元素,设当前sq->front为20,sq-&g…

谷歌推大语言模型VideoPoet:文本图片皆可生成视频和音频

Google Research最近发布了一款名为VideoPoet的大型语言模型(LLM),旨在解决当前视频生成领域的挑战。该领域近年来涌现出许多视频生成模型,但在生成连贯的大运动时仍存在瓶颈。现有领先模型要么生成较小的运动,要么在生…