尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
建造者模式详解:原理、实现与应用场景
1. 为什么我们需要建造者模式上周团队里有个刚毕业的新同事提交了一段创建订单对象的代码我一看就乐了——构造方法足足有15个参数这种代码别说维护了连调用的时候都容易传错参数顺序。这正是建造者模式要解决的典型场景。建造者模式Builder Pattern属于创建型设计模式它特别适合以下三种情况当对象需要多个初始化参数且这些参数之间存在复杂的组合关系时当对象的构造过程需要分步骤进行且不同场景需要不同的构造流程时当需要创建不可变对象但又想保持代码可读性时提示建造者模式与工厂模式最大的区别在于工厂模式关注整体对象的创建而建造者模式关注对象各部分的有序组装。1.1 建造者模式的核心思想想象你在麦当劳点餐你不需要记住所有套餐组合而是通过汉堡薯条可乐这样的分步选择完成点单。建造者模式也是这样工作的将复杂对象的构造过程拆分为多个独立步骤通过统一的指挥者Director控制组装流程最终产出完整产品这种模式完美遵循了单一职责原则——对象构造的每个步骤都独立变化也符合开闭原则——新增产品类型时无需修改现有代码。2. 建造者模式的四种实现方式2.1 经典建造者实现这是《设计模式》原书中标准的实现方式包含四个角色// 产品类 class Computer { private String cpu; private String memory; // 其他组件... // 只提供setter方法确保不可变 public void setCpu(String cpu) { this.cpu cpu; } } // 抽象建造者 interface ComputerBuilder { void buildCpu(); void buildMemory(); Computer getResult(); } // 具体建造者 class GamingComputerBuilder implements ComputerBuilder { private Computer computer new Computer(); Override public void buildCpu() { computer.setCpu(i9-13900K); } // 其他实现... } // 指挥者 class Director { public Computer construct(ComputerBuilder builder) { builder.buildCpu(); builder.buildMemory(); return builder.getResult(); } }这种实现最规范但代码量也最大。适合需要支持多种产品类型的复杂场景。2.2 流式建造者链式调用这是Java开发中最常见的实现方式Lombok的Builder注解就是这种风格public class User { private final String name; // final确保不可变 private final int age; private User(Builder builder) { this.name builder.name; this.age builder.age; } public static class Builder { private String name; private int age; public Builder name(String name) { this.name name; return this; // 返回this实现链式调用 } public User build() { return new User(this); } } } // 使用示例 User user new User.Builder() .name(张三) .age(25) .build();实测发现这种写法有三大优势代码可读性极强就像在说创建一个用户名字叫张三年龄25参数顺序灵活可以任意组合天然支持参数校验在build()方法中2.3 静态内部类变体这是Joshua Bloch在《Effective Java》中推荐的写法public class NutritionFacts { private final int servingSize; private final int calories; public static class Builder { // 必选参数 private final int servingSize; // 可选参数带默认值 private int calories 0; public Builder(int servingSize) { this.servingSize servingSize; } public Builder calories(int val) { calories val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } private NutritionFacts(Builder builder) { servingSize builder.servingSize; calories builder.calories; } }这种写法特别适合既有必选参数又有可选参数的场景。我在电商系统中创建订单对象时就采用了这种模式。2.4 函数式实现Java 8利用Supplier函数接口可以实现非常灵活的建造者public class FunctionalBuilderT { private final SupplierT instantiator; private ListConsumerT modifiers new ArrayList(); public FunctionalBuilder(SupplierT instantiator) { this.instantiator instantiator; } public static T FunctionalBuilderT of(SupplierT instantiator) { return new FunctionalBuilder(instantiator); } public U FunctionalBuilderT with(BiConsumerT, U consumer, U value) { modifiers.add(instance - consumer.accept(instance, value)); return this; } public T build() { T value instantiator.get(); modifiers.forEach(modifier - modifier.accept(value)); modifiers.clear(); return value; } } // 使用示例 Person person FunctionalBuilder.of(Person::new) .with(Person::setName, 李四) .with(Person::setAge, 30) .build();这种写法虽然炫酷但团队新人理解成本较高建议只在函数式编程经验丰富的团队中使用。3. 建造者模式的实战应用3.1 MyBatis中的建造者模式MyBatis的SqlSessionFactoryBuilder就是建造者模式的经典案例SqlSessionFactory factory new SqlSessionFactoryBuilder() .build(inputStream); // 背后其实是分步构建 public SqlSessionFactory build(InputStream inputStream) { // 1. 解析配置 XMLConfigBuilder parser new XMLConfigBuilder(inputStream); // 2. 创建配置对象 Configuration config parser.parse(); // 3. 创建工厂 return build(config); }这种设计让配置解析和工厂创建解耦后续MyBatis新增XML以外的配置方式如注解配置时完全不需要修改SqlSessionFactoryBuilder的代码。3.2 JDK中的建造者模式Java标准库中也有不少建造者模式的应用StringBuilder/StringBuffer通过append()方法逐步构建字符串Stream API通过流式操作构建最终结果DateTimeFormatterBuilder构建复杂的时间格式化器特别值得注意的是这些JDK内置的建造者都采用了可变对象设计因为字符串、时间格式这些对象本身就需要频繁修改。3.3 Spring中的建造者模式Spring框架中有个不太为人知但非常有用的建造者——BeanDefinitionBuilderBeanDefinitionBuilder builder BeanDefinitionBuilder .rootBeanDefinition(MyService.class) .addPropertyValue(timeout, 1000) .setInitMethodName(init); // 注册到容器 context.registerBeanDefinition(myService, builder.getBeanDefinition());在需要动态注册Bean的场景如自定义Starter开发中这个建造者能大幅简化代码。4. 建造者模式的进阶技巧4.1 与工厂模式结合使用建造者模式负责对象组装工厂模式负责对象创建二者可以完美配合public interface PizzaFactory { PizzaBuilder createBuilder(PizzaType type); } public class PizzaShop { private PizzaFactory factory; public Pizza orderPizza(PizzaType type) { PizzaBuilder builder factory.createBuilder(type); return new PizzaDirector().construct(builder); } }这种组合在需要创建复杂对象家族时特别有用比如电商系统中的订单子系统。4.2 实现级联建造者当对象包含嵌套对象时可以设计级联建造者public class Order { private ListOrderItem items; public static class Builder { private ListOrderItem.Builder itemBuilders new ArrayList(); public OrderItem.Builder addItem() { OrderItem.Builder builder new OrderItem.Builder(); itemBuilders.add(builder); return builder; } public Order build() { Order order new Order(); order.items itemBuilders.stream() .map(OrderItem.Builder::build) .collect(Collectors.toList()); return order; } } }这样在创建订单时可以流畅地添加多个订单项Order order new Order.Builder() .addItem().product(p1).quantity(2).up() .addItem().product(p2).quantity(1).up() .build();4.3 线程安全的建造者实现如果建造者需要在多线程环境下使用可以采用这些策略防御性拷贝在build()方法中创建新对象时复制所有参数不可变建造者所有setter方法都返回新建造者实例同步控制对关键方法加synchronized性能较差5. 常见问题与性能优化5.1 建造者模式的内存开销每个建造者实例都会持有产品对象的引用在需要创建大量对象时可能引发内存问题。解决方案重用建造者实例调用build()后重置状态使用对象池管理建造者对于简单对象改用静态工厂方法5.2 与Lombok Builder的兼容问题Lombok的Builder很方便但有几个坑需要注意与AllArgsConstructor冲突需要显式添加AllArgsConstructor(access AccessLevel.PRIVATE)继承问题父类的字段不会自动包含在建造者中默认值设置需要在字段上直接初始化而不是在建造者中5.3 建造者模式的单元测试测试建造者时应该关注建造者方法是否正确地设置了属性build()方法是否执行了必要的参数校验不同建造者组合是否产生预期结果建议采用行为验证而非状态验证Test void shouldSetCpuWhenBuildComputer() { ComputerBuilder builder mock(ComputerBuilder.class); Director director new Director(); director.construct(builder); verify(builder).buildCpu(); verify(builder).buildMemory(); }6. 什么情况下不该用建造者模式虽然建造者模式很强大但也不是银弹。以下情况不建议使用对象创建非常简单少于4个参数参数之间没有复杂的依赖关系不需要创建不可变对象性能敏感的场景建造者会有额外对象创建开销我在实际项目中的经验法则是当发现自己在写超过3个参数的构造函数时就该考虑改用建造者模式了。
RELATED

相关推荐

大模型Agent开发入门:从框架选型到实战避坑全攻略

大模型Agent开发入门:从框架选型到实战避坑全攻略

经常有朋友拿同样的问题来问我:大模型看起来什么都懂,可真让它去干活,怎么就跟丢了魂似的?我的回答一般很直接——因为大多数人用大模型的方式,是把它当搜索引擎和聊天对象,而不是把它放进一个完整的Agent系…

📅 2026/10/31 13:03:22
基于二阶锥松弛的配电网无功优化技术解析

基于二阶锥松弛的配电网无功优化技术解析

1. 项目背景与核心目标 在现代电力系统中,随着分布式能源渗透率的不断提高,配电网的无功优化问题变得愈发复杂。传统的集中式发电模式正在向"源-网-荷-储"协同互动的主动配电网转变,这对无功电压控制提出了更高要求。本项目正是针对…

📅 2026/10/31 13:03:22
博士论文送印前一天,我把封面和目录反复对了三遍,硕词AI(官方网站:www.shuociai.com)提醒还有两处要查

博士论文送印前一天,我把封面和目录反复对了三遍,硕词AI(官方网站:www.shuociai.com)提醒还有两处要查

送印前一天晚上,我把博士论文最终稿打印出来,摊在桌上,封面和目录反复对了三遍。封面的专业名称、指导教师、提交日期,逐字和学校模板核对;目录上每一章的页码,随手翻到那一页亲手比过。我以为这样就万无一…

📅 2026/10/31 13:03:22
MORE NEWS

更多资讯

📰

AI原生SDLC设计阶段:从需求到可执行提示词的工程实践

1. AI 原生 SDLC 中的设计环节到底在解决什么问题1.1 从“写代码”到“设计意图”的范式转移传统软件开发生命周期里,设计阶段往往被压缩成几页文档、几张架构图,然后大家就急着进入编码。但在 AI 原生 SDLC 的语境下,设计环节的权重被大幅拉…

📰

AI论文写作工具:提升学术效率与质量的核心利器

1. AI论文写作工具的核心价值解析 在学术写作领域,AI工具正在引发一场静默的革命。作为一名长期从事学术研究的从业者,我见证了从纯手工写作到智能辅助的完整演进过程。当前主流的AI论文工具已经能够处理文献综述、结构搭建、数据分析甚至初稿生成等核心…

📰

secs4net源码深度解析:GEM协议调试与SECS报文故障定位

简介:本资源为面向半导体设备自动化领域的SECS/GEM通信协议开源实现项目secs4net,适用于工业软件开发者、自动化工程师及协议学习者,用于快速理解、调试与集成SECS/GEM设备通信功能。压缩包共320个文件,以191个C#源码(…

📰

冰面漂移中的MPC控制算法优化与实践

1. 冰面漂移中的MPC控制挑战 冰面漂移对控制算法提出了三个维度的极限要求:首先是极低的路面摩擦系数(μ≈0.1-0.2),传统轮胎侧向力模型在冰面上呈现高度非线性;其次是车辆动力学状态的快速变化,漂移过程中…

📰

拷贝目录内所有文件到指定目录exe工具:从批处理到Python打包全攻略

简介:面向需要在Windows 64位环境下批量整理文件的使用者,这款工具可将指定目录下的所有文件(包括任意层级子目录中的文件)一键拷贝至目标目录,适用于资料归档、项目部署、迁移备份等场景,能有效提高日常文…

📰

Trae AI编程编辑器:从安装到实战的完整指南

1. 为什么选择Trae AI编程编辑器作为你的第一个开发工具? 作为一个从传统编辑器转型到AI编程工具的开发者,我清楚地记得第一次使用Trae时的震撼。当时我正在为一个客户紧急修改网页布局,在传统编辑器里反复修改CSS却始终达不到理想效果。而Tr…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬