模式:用 java-design-patterns 仓库源码吃透对象构建)
示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载本篇技术指南以 localization/ko/builder/README.md韩文版 Builder 模式文档为核心骨架结合本仓库builder模块的真实源码、枚举定义与单元测试进行深度展开。你将理解 Builder 模式如何解决伸缩构造函数反模式telescoping constructor anti-pattern掌握其类结构、链式调用写法、参数校验策略与适用场景并看到它在 JDK 与流行框架中的真实应用。设计意图IntentBuilder 是一种创建型设计模式其核心意图是将复杂对象的构建过程与其最终表示分离使得同一个构建过程可以产出不同的对象表示。用一句话概括我们不再直接通过构造函数一次性传齐所有参数而是借助一个独立的构建者对象分步地、可读地、可校验地组装目标对象最后再一次性产出最终产物。这在 java-design-patterns 仓库中对应 builder 模块其分类标签为Creational创建型与Gang of FourGoF 经典四人组模式。要解决的问题伸缩构造函数反模式Telescoping Constructor Anti-pattern为什么需要 Builder文档中给出了一个几乎所有 Java 开发者都见过的痛点——构造参数过多的构造函数public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) { // 参数赋值 }问题显而易见参数数量迅速失控当可选属性越来越多时构造函数的形参列表不断膨胀调用方难以记忆每个参数的位置与含义可读性差new Hero(Profession.MAGE, Riobard, HairType.BALD, HairColor.BLACK, null, Weapon.DAGGER)这类代码里null的位置含义模糊极易传错扩展性差后续每增加一个可选属性要么继续加参数要么新增重载构造函数最终形成望远镜式层层叠加的构造函数爆炸。这正是 Wikipedia 对 Builder 模式的定义背景——Builder 模式是旨在解决伸缩构造函数反模式的对象创建型软件设计模式。仓库源码实现Hero 与 Builder 的完整结构本仓库的 builder/src/main/java/com/iluwatar/builder 包中给出了一个基于 RPG 角色生成场景的完整示例。角色创建是一个典型的分步过程职业、姓名是必填项而发型、发色、护甲、武器都是可选项选择全部完成后角色才最终生成。目标对象 HeroHero.java中Hero被定义为一个recordJava 16 特性所有字段均为final天然不可变public record Hero( Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) { private Hero(Builder builder) { this( builder.profession, builder.name, builder.hairType, builder.hairColor, builder.armor, builder.weapon); } // toString() 省略 }要点分析构造函数是private的外部无法直接new Hero(...)只能经由Builder间接创建从语言层面强制了构建流程的唯一入口对象不可变record 的访问器方法profession()、name()等只读构建完成后对象状态不会改变天然线程安全、便于缓存与共享构造即拷贝私有构造函数从 builder 的各字段拷贝到 record 的规范构造函数完成快照式赋值。构建者 BuilderHero.Builder是嵌套在Hero内部的public static类文档中称之为the builder它的设计体现了 Builder 模式的经典三要素角色实现方式必填参数放入Builder构造函数并做非空校验可选参数通过withXxx(...)链式方法逐步设置方法返回this终止方法build()一次性调用私有构造函数产出最终对象public static class Builder { private final Profession profession; // 必填final private final String name; // 必填final private HairType hairType; // 可选 private HairColor hairColor; // 可选 private Armor armor; // 可选 private Weapon weapon; // 可选 public Builder(Profession profession, String name) { if (profession null || name null) { throw new IllegalArgumentException(profession and name can not be null); } this.profession profession; this.name name; } public Builder withHairType(HairType hairType) { this.hairType hairType; return this; } public Builder withHairColor(HairColor hairColor) { this.hairColor hairColor; return this; } public Builder withArmor(Armor armor) { this.armor armor; return this; } public Builder withWeapon(Weapon weapon) { this.weapon weapon; return this; } public Hero build() { return new Hero(this); } }几个值得细读的源码细节必填参数的强约束Builder构造函数内显式抛出IllegalArgumentException杜绝了职业或姓名为空的角色对象产生。这是文档中점층적 생성자 안티-패턴에 대한 해결책对伸缩构造函数反模式的解决方案在代码层面的落地流式接口Fluent Interface每个withXxx方法返回this使调用可以连续拼接可选参数不设置即为null最终toString()中会对空值做条件判断见 Hero.java如hairType ! HairType.BALD ? hair : head的趣味处理单步产出build()是唯一的出口调用时一次性完成对象组装符合App.java中configuration is ready then call build method的流程描述。支撑枚举可选项的取值域构建过程中用到的各属性均为枚举它们的定义含toString()映射为构建者提供了清晰的取值集合枚举文件路径取值ProfessionProfession.javaWARRIOR、THIEF、MAGE、PRIESTHairTypeHairType.javaBALD、SHORT、CURLY、LONG_STRAIGHT、LONG_CURLYHairColorHairColor.javaWHITE、BLOND、RED、BROWN、BLACKArmorArmor.javaCLOTHES、LEATHER、CHAIN_MAIL、PLATE_MAILWeaponWeapon.javaDAGGER、SWORD、AXE、WARHAMMER、BOW其中HairType与Armor使用 Lombok 的AllArgsConstructor绑定展示文案如LONG_CURLY显示为 long curlyProfession等则重写toString()返回小写枚举名——这也解释了程序输出中This is a mage named Riobard这类自然语言句子的来源。使用方式与运行输出App.java的main方法演示了三种不同风味的角色构建充分体现同一构建过程、不同对象表示var mage new Hero.Builder(Profession.MAGE, Riobard) .withHairColor(HairColor.BLACK) .withWeapon(Weapon.DAGGER) .build(); LOGGER.info(mage.toString()); var warrior new Hero.Builder(Profession.WARRIOR, Amberjill) .withHairColor(HairColor.BLOND) .withHairType(HairType.LONG_CURLY) .withArmor(Armor.CHAIN_MAIL) .withWeapon(Weapon.SWORD) .build(); LOGGER.info(warrior.toString()); var thief new Hero.Builder(Profession.THIEF, Desmond) .withHairType(HairType.BALD) .withWeapon(Weapon.BOW) .build(); LOGGER.info(thief.toString());程序输出与文档记录一致16:28:06.058 [main] INFO com.iluwatar.builder.App -- This is a mage named Riobard with black hair and wielding a dagger. 16:28:06.060 [main] INFO com.iluwatar.builder.App -- This is a warrior named Amberjill with blond long curly hair wearing chain mail and wielding a sword. 16:28:06.060 [main] INFO com.iluwatar.builder.App -- This is a thief named Desmond with bald head and wielding a bow.注意三个角色的构建差异mage 只设置了发色与武器warrior 补全了全部可选属性thief 则只设了发型与武器——可选属性完全按需组合这正是 Builder 相比全参构造函数的核心优势。运行方式也很简单在 IDE 中直接执行App.main或在仓库根目录通过 Maven 运行对应测试。模式类图与调用时序文档中的类图./etc/builder.urm.png展示了Hero、Builder与各枚举之间的静态关系builder/etc/builder.urm.puml 是它的 PlantUML 源文件仓库还额外提供了时序图 builder/etc/builder-sequence-diagram.png 说明运行时调用链。从时序上看调用流程为new Hero.Builder(必填参数)→ 零到多次.withXxx(可选参数)→.build()返回不可变的Hero实例。整个过程中调用方完全不需要知道Hero内部有多少字段、如何组装。适用场景Applicability根据文档与源码以下情况适合使用 Builder 模式复杂对象的构造算法应与组成部分及组装方式解耦——即怎么拼与拼什么互不依赖构建过程需要允许同一对象产生不同表示——例如同一个Hero.Builder流程可产出法师、战士、盗贼三种形态产品需要大量步骤才能创建且步骤需要按特定顺序执行顺序约束可由 builder 内部方法设计保证可选参数多、必填参数少的场景用于规避伸缩构造函数反模式。此外App.java 的类注释还补充了一个容易被忽略的适用场景对象包含扁平数据如 HTML 代码、SQL 查询、X.509 证书时这类数据无法逐步编辑、必须一次性整体生成builder 是构造它们的最佳方式。单元测试验证仓库提供了完整的测试用例来印证 Builder 的契约行为HeroTest.javatestMissingProfessionnew Hero.Builder(null, Sir without a job)断言抛出IllegalArgumentExceptiontestMissingNamenew Hero.Builder(Profession.THIEF, null)同样断言抛异常——验证必填参数校验逻辑testBuildHero完整构建一个骑士角色后逐一断言profession()、name()、armor()、weapon()、hairType()、hairColor()与设置值一致——验证 builder 正确将配置传递给了最终对象AppTest.java断言App.main可无异常执行确保示例程序可运行。优点与权衡Benefits and Trade-offs优点相比其他创建型模式对构建过程有更强的控制力——可以分步构建、延迟执行某些步骤甚至递归执行步骤支持需要复杂子对象组装的场景最终产品与其组成部分及组装过程完全解耦符合单一职责原则把复杂的构造代码从产品业务逻辑中隔离出来参数校验集中、可读性高、产物不可变。权衡由于需要额外创建 builder 类整体代码复杂度会上升多个 builder 对象的创建可能带来额外的内存占用。与仓库中其他模式的关联在 java-design-patterns 仓库中Builder 并非孤立存在它与若干模式相互配合抽象工厂Abstract Factory可与 Builder 联合使用由抽象工厂负责构建复杂对象的零部件Builder 负责装配流程原型PrototypeBuilder 常基于原型对象进行定制化复制构建逐步构建者Step Builder仓库 step-builder 模块是其变体——当可选参数非常多、且需要编译期强制按步骤构建时Step Builder 通过接口类型逐步引导调用顺序同样是伸缩构造函数反模式的替代方案。真实世界应用案例Builder 模式在 Java 生态中随处可见文档列举了以下经典实例java.lang.StringBuilder——最广为人知的字符串构建器java.lang.StringBuffer——线程安全的可变字符串构建器java.nio.ByteBuffer及其同类缓冲区FloatBuffer、IntBuffer等——通过链式put分步填充数据所有实现了java.lang.Appendable的类型Apache Camel 的 builder 工具集org.apache.camel.builder包用于分步构建路由与 DSLApache Commons CLI 的Option.Builder用于链式组装命令行选项。这些实例的共同特征构建对象包含大量可选配置且希望最终对象不可变或一次性生成与本文Hero.Builder的动机完全一致。参考资料与延伸阅读本模块内容与以下经典著作一脉相承可作深入学习参考Design Patterns: Elements of Reusable Object-Oriented SoftwareGoF 四人组经典Effective Java——Joshua Bloch 提出的 Builder 变体正是本仓库Hero.Builder的蓝本见 App.java 类注释中的明确说明Head First Design PatternsRefactoring to Patterns如需查看英文原版说明与完整示例可对照仓库根级文档 builder/README.md其与韩文版 localization/ko/builder/README.md 共同维护同一份builder模块的技术说明二者互为印证。赞分享示例工程教程【免费下载链接】java-design-patternsDesign patterns implemented in Java项目地址https://gitcode.com/GitHub_Trending/ja/java-design-patterns点击查看免费下载相关推荐Java 设计模式之 Builder建造者模式java-design-patterns 仓库中的 Hero 构建实战Java 设计模式之 Builder建造者模式java design patterns 仓库中的 Hero 构建实战 Builder建造者模式是 Ja示例工程教程Java 设计模式之 Builder 构建器模式在 java-design-patterns 中用清晰的方式构造复杂对象Java 设计模式之 Builder 构建器模式在 java design patterns 中用清晰的方式构造复杂对象 Builder构建器是一种创建型示例工程教程Java 设计模式之 Context Object上下文对象模式java-design-patterns 仓库源码级解读与实战指南Java 设计模式之 Context Object上下文对象模式java design patterns 仓库源码级解读与实战指南 导读 本文以 java示例工程教程上一篇MiniMind快速本地部署轻量GPT跑起来 WebUI搭建下一篇深度解析Video2X构建高性能视频超分辨率与帧插值应用的全栈实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考