0

0

如何实现Java的建造者模式(Builder)_复杂对象构建方案

P粉602998670

P粉602998670

发布时间:2026-03-06 11:30:19

|

658人浏览过

|

来源于php中文网

原创

builder 类不必是静态内部类,但强烈建议;build() 应在最后统一校验;lombok @builder 多数场景可用,但有三限制;链式调用返回 this 为提效与保序,但不线程安全。

如何实现java的建造者模式(builder)_复杂对象构建方案

Builder 类必须是目标类的静态内部类吗?

不是必须,但强烈建议。非静态内部类会隐式持有外部类实例引用,可能引发内存泄漏或意外状态耦合;而 static 内部类更轻量、语义更清晰,也方便单独测试。

  • 如果 Builder 需要访问目标类的私有字段(比如做校验),用 static + 友元式构造(通过 public 构造函数传参)比非静态更可控
  • 若 Builder 被提取为顶级类(如 PersonBuilder),务必确保它和目标类(如 Person)版本同步,否则容易出现字段不一致导致的 NullPointerException
  • IDE 自动生成 Builder 时(如 Lombok 的 @Builder),默认生成 static,别手动改成非静态除非真有跨生命周期共享状态的需求

build() 方法里该不该做参数校验?

应该做,而且得在 build() 调用时一次性校验,不是在每个 withXxx() 方法里分散校验。

  • 提前校验(比如在 withName(String) 里 throw NullPointerException)会导致链式调用中断,用户无法“先设完再统一检查”
  • 延迟到 build() 才校验,能收集所有必填字段缺失情况,报错信息可合并(例如:“name 和 age 都不能为空”),体验更好
  • 注意校验逻辑不要依赖外部状态(如数据库、系统时间),否则 build() 就不再是纯函数,难以单元测试

Lombok 的 @Builder 能直接替代手写 Builder 吗?

大多数场景可以,但要注意三个硬限制:

Img.Upscaler
Img.Upscaler

免费的AI图片放大工具

下载
  • 不支持条件性必填字段(比如“如果设置了 type = "VIP",则 vipLevel 必须非空”),Lombok 生成的 build() 没法插入手动校验逻辑
  • 生成的 Builder 类名默认是 TargetClass.Builder,但如果目标类已存在静态内部类 Builder,Lombok 会静默失败,编译报错提示 “duplicate class”,得加 @Builder(builderClassName = "CustomBuilder")
  • 泛型类型推导有时不准,比如构建 List<string></string> 字段时,builder.items(Arrays.asList("a")) 可能触发类型擦除问题,需显式写成 builder.<string>items(...)</string>

为什么链式调用返回 this 而不是新 Builder 实例?

为了节省对象分配开销,并保证调用顺序与字段赋值顺序严格一致。每次 new 一个 Builder 实例看似“不可变”,实则破坏了构建上下文的连贯性。

立即学习Java免费学习笔记(深入)”;

  • 返回新实例会让用户误以为调用 withName("A").withName("B") 最终 name 是 "B" —— 确实如此,但中间那个带 "A" 的 Builder 白建了,GC 压力增大
  • 返回 this 是主流做法,但要注意线程不安全:Builder 实例不能被多个线程共用,否则会出现字段覆盖(比如 A 线程 set age=20,B 线程 set age=30,最终 build 出来可能是 30,也可能因指令重排出错)
  • 如果真需要线程安全构建,别用链式,改用传统 setter + 显式 build(),或者用不可变 Builder(每次 set 都 copy 新实例),但代价是堆内存翻倍
复杂对象构建真正难的不是语法,是校验边界和生命周期归属——Builder 拿到的字段值,到底该由谁负责验证合法性?又该由谁决定它何时失效?这些不会在 IDE 里高亮,但会在上线后某个凌晨三点的报警里突然浮现。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

950

2023.08.02

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

434

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

600

2023.08.10

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

788

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

26

2025.12.06

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

743

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

743

2023.08.10

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

382

2023.06.29

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

1

2026.03.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.2万人学习

C# 教程
C# 教程

共94课时 | 10.8万人学习

Java 教程
Java 教程

共578课时 | 77.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号