设计模式系列(07):建造者模式(Builder)

本文为设计模式系列第7篇,聚焦创建型模式中的建造者模式,涵盖定义、原理、实际业务场景、优缺点、最佳实践及详细代码示例,适合系统学习与实战应用。


目录

  • 1. 模式概述
  • 2. 使用场景
  • 3. 优缺点分析
  • 4. 实际应用案例
  • 5. 结构与UML类图
  • 6. 代码示例
  • 7. 测试用例
  • 8. 常见误区与反例
  • 9. 最佳实践
  • 10. 参考资料与延伸阅读

1. 模式概述

建造者模式(Builder Pattern)是一种创建型设计模式。它将复杂对象的构建与表示分离,使同样的构建过程可以创建不同的表示。适用于需要分步骤、可定制、部件复杂的对象创建。

1.1 定义

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

1.2 目的

  • 分离构建过程与表示,支持灵活扩展
  • 简化复杂对象的创建,隐藏细节
  • 支持多种产品配置和复用

2. 使用场景

建造者模式在实际开发中应用广泛,常见场景包括:

  1. 复杂对象组装:如汽车、电脑、房屋等多部件组装,步骤复杂且可定制。
  2. 文档/报表生成:如HTML、PDF、Word等多格式文档的分步生成。
  3. UI表单/界面构建:如动态表单、复杂界面分步渲染。
  4. 配置对象创建:如系统配置、网络配置等参数众多且组合灵活的对象。

真实业务背景举例:

  • 电商平台订单对象包含商品、收货、支付、优惠等多个可选部件,建造者模式可灵活组装。
  • SaaS平台支持多种报表格式导出,建造者模式可统一流程、灵活扩展。
  • 游戏角色装备、技能、属性等复杂对象,建造者模式便于分步构建和扩展。

3. 优缺点分析

3.1 优点

  1. 封装性:隐藏构建细节,客户端无需关心内部实现。
  2. 灵活性:支持不同产品配置和多种表示。
  3. 可维护性:构建过程独立,便于扩展和维护。

3.2 缺点

  1. 类数量增加:每种产品/部件都需建造者类,结构复杂。
  2. 适用范围有限:只适用于部件复杂、构建过程稳定的对象。
  3. 构建过程固定:如步骤变化大,需频繁修改建造者接口。

4. 实际应用案例

  1. 订单对象组装:商品、收货、支付、优惠等分步组装。
  2. 报表/文档生成:多格式报表、文档的统一生成流程。
  3. 汽车/电脑组装:多部件、可选配置的复杂对象。
  4. UI表单构建:动态表单、复杂界面分步渲染。

5. 结构与UML类图

@startuml
package "Builder Pattern" #DDDDDD {class Computer {+ setCpu(cpu: String): void+ setRam(ram: String): void+ setStorage(storage: String): void+ setGpu(gpu: String): void}interface ComputerBuilder {+ buildCpu(): void+ buildRam(): void+ buildStorage(): void+ buildGpu(): void+ getResult(): Computer}class GamingComputerBuilder implements ComputerBuilderclass OfficeComputerBuilder implements ComputerBuilderclass ComputerEngineer {- builder: ComputerBuilder+ constructComputer(): void}ComputerBuilder <|.. GamingComputerBuilderComputerBuilder <|.. OfficeComputerBuilderComputerEngineer o-- ComputerBuilder : builderGamingComputerBuilder --> Computer : getResult()OfficeComputerBuilder --> Computer : getResult()
}
@enduml

6. 代码示例

6.1 基本结构示例

业务背景: 电脑组装业务,支持多种配置,分步构建。

// 产品类:电脑
package com.example.patterns.builder;import java.util.Objects;
import java.util.StringJoiner;public class Computer {private String cpu;private String ram;private String storage;private String gpu;public void setCpu(String cpu) { this.cpu = Objects.requireNonNull(cpu, "CPU cannot be null"); }public void setRam(String ram) { this.ram = Objects.requireNonNull(ram, "RAM cannot be null"); }public void setStorage(String storage) { this.storage = Objects.requireNonNull(storage, "Storage cannot be null"); }public void setGpu(String gpu) { this.gpu = Objects.requireNonNull(gpu, "GPU cannot be null"); }// 改进的toString方法@Overridepublic String toString() {return new StringJoiner(", ", "Computer{", "}").add("cpu='" + cpu + "'").add("ram='" + ram + "'").add("storage='" + storage + "'").add("gpu='" + gpu + "'").toString();}// 添加equals和hashCode方法,便于测试@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Computer computer = (Computer) o;return Objects.equals(cpu, computer.cpu) &&Objects.equals(ram, computer.ram) &&Objects.equals(storage, computer.storage) &&Objects.equals(gpu, computer.gpu);}@Overridepublic int hashCode() {return Objects.hash(cpu, ram, storage, gpu);}
}// 抽象建造者
public interface ComputerBuilder {void buildCpu();void buildRam();void buildStorage();void buildGpu();Computer getResult();// 添加重置方法,支持builder复用default void reset() {// 子类可以重写此方法实现重置逻辑}
}// 游戏电脑建造者
public class GamingComputerBuilder implements ComputerBuilder {private Computer computer = new Computer();@Overridepublic void buildCpu() { computer.setCpu("Intel i9-13900K"); }@Overridepublic void buildRam() { computer.setRam("32GB DDR5"); }@Overridepublic void buildStorage() { computer.setStorage("2TB NVMe SSD"); }@Overridepublic void buildGpu() { computer.setGpu("NVIDIA RTX 4090"); }@Overridepublic Computer getResult() { return computer; }@Overridepublic void reset() {computer = new Computer();}
}// 办公电脑建造者
public class OfficeComputerBuilder implements ComputerBuilder {private Computer computer = new Computer();@Overridepublic void buildCpu() { computer.setCpu("Intel i5-13600K"); }@Overridepublic void buildRam() { computer.setRam("16GB DDR4"); }@Overridepublic void buildStorage() { computer.setStorage("1TB SATA SSD"); }@Overridepublic void buildGpu() { computer.setGpu("Intel UHD Graphics"); }@Overridepublic Computer getResult() { return computer; }@Overridepublic void reset() {computer = new Computer();}
}// 组装工程师(导演类)
public class ComputerEngineer {private ComputerBuilder builder;public ComputerEngineer(ComputerBuilder builder) { this.builder = Objects.requireNonNull(builder, "Builder cannot be null"); }public void constructComputer() {builder.reset(); // 确保从干净状态开始builder.buildCpu();builder.buildRam();builder.buildStorage();builder.buildGpu();}// 添加部分构建方法,支持定制化public void constructBasicComputer() {builder.reset();builder.buildCpu();builder.buildRam();builder.buildStorage();// 不添加独显}
}// 客户端示例
public class Client {public static void main(String[] args) {try {// 创建游戏电脑ComputerBuilder gamingBuilder = new GamingComputerBuilder();ComputerEngineer gamingEngineer = new ComputerEngineer(gamingBuilder);gamingEngineer.constructComputer();Computer gamingComputer = gamingBuilder.getResult();System.out.println("Gaming Computer: " + gamingComputer);// 创建办公电脑ComputerBuilder officeBuilder = new OfficeComputerBuilder();ComputerEngineer officeEngineer = new ComputerEngineer(officeBuilder);officeEngineer.constructComputer();Computer officeComputer = officeBuilder.getResult();System.out.println("Office Computer: " + officeComputer);} catch (Exception e) {System.err.println("Failed to build computer: " + e.getMessage());}}// 总结:通过建造者模式,客户端可灵活组装不同配置电脑,便于扩展和维护。
}

6.2 实际业务场景:订单对象建造者

业务背景: 电商平台订单对象包含商品、收货、支付、优惠等多个可选部件,建造者模式可灵活组装。

// 订单对象
package com.example.patterns.builder.order;import java.math.BigDecimal;
import java.util.Objects;
import java.util.StringJoiner;public class Order {private String product;private String address;private String payment;private String discount;private BigDecimal amount; // 添加金额字段public void setProduct(String product) { this.product = product; }public void setAddress(String address) { this.address = address; }public void setPayment(String payment) { this.payment = payment; }public void setDiscount(String discount) { this.discount = discount; }public void setAmount(BigDecimal amount) { this.amount = amount; }public String getProduct() { return product; }public String getAddress() { return address; }public String getPayment() { return payment; }public String getDiscount() { return discount; }public BigDecimal getAmount() { return amount; }// 校验订单是否有效public boolean isValid() {return product != null && !product.trim().isEmpty() &&address != null && !address.trim().isEmpty() &&payment != null && !payment.trim().isEmpty() &&amount != null && amount.compareTo(BigDecimal.ZERO) > 0;}@Overridepublic String toString() {return new StringJoiner(", ", "Order{", "}").add("product='" + product + "'").add("address='" + address + "'").add("payment='" + payment + "'").add("discount='" + discount + "'").add("amount=" + amount).toString();}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Order order = (Order) o;return Objects.equals(product, order.product) &&Objects.equals(address, order.address) &&Objects.equals(payment, order.payment) &&Objects.equals(discount, order.discount) &&Objects.equals(amount, order.amount);}@Overridepublic int hashCode() {return Objects.hash(product, address, payment, discount, amount);}
}// 订单建造者
public class OrderBuilder {private Order order = new Order();public OrderBuilder product(String product) { if (product == null || product.trim().isEmpty()) {throw new IllegalArgumentException("Product cannot be null or empty");}order.setProduct(product); return this; }public OrderBuilder address(String address) { if (address == null || address.trim().isEmpty()) {throw new IllegalArgumentException("Address cannot be null or empty");}order.setAddress(address); return this; }public OrderBuilder payment(String payment) { if (payment == null || payment.trim().isEmpty()) {throw new IllegalArgumentException("Payment method cannot be null or empty");}order.setPayment(payment); return this; }public OrderBuilder discount(String discount) { // 折扣是可选的,允许nullorder.setDiscount(discount); return this; }public OrderBuilder amount(BigDecimal amount) {if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {throw new IllegalArgumentException("Amount must be positive");}order.setAmount(amount);return this;}// 便捷方法,接受double类型public OrderBuilder amount(double amount) {return amount(BigDecimal.valueOf(amount));}public Order build() { if (!order.isValid()) {throw new IllegalStateException("Order is not valid. Missing required fields.");}return order; }// 重置建造者,支持复用public OrderBuilder reset() {order = new Order();return this;}
}// 客户端示例
public class OrderClient {public static void main(String[] args) {try {// 创建完整订单Order order = new OrderBuilder().product("iPhone 15 Pro").address("上海市浦东新区").payment("微信支付").discount("满1000减100").amount(8999.00).build();System.out.println("订单信息: " + order);// 创建无折扣订单Order simpleOrder = new OrderBuilder().product("MacBook Pro").address("北京市朝阳区").payment("支付宝").amount(15999.00).build();System.out.println("简单订单: " + simpleOrder);} catch (IllegalArgumentException | IllegalStateException e) {System.err.println("订单创建失败: " + e.getMessage());}}// 总结:通过链式建造者和参数校验,订单对象组装更安全,代码简洁易维护。
}

7. 测试用例

业务背景: 验证电脑建造者和订单建造者的核心功能与多实现切换。

public class BuilderPatternTest {@Testpublic void testGamingComputer() {ComputerBuilder builder = new GamingComputerBuilder();ComputerEngineer engineer = new ComputerEngineer(builder);// 构建游戏电脑engineer.constructComputer();Computer computer = builder.getResult();// 验证游戏电脑配置String computerStr = computer.toString();assertTrue(computerStr.contains("Intel i9-13900K"));assertTrue(computerStr.contains("32GB DDR5"));assertTrue(computerStr.contains("NVIDIA RTX 4090"));}@Testpublic void testOfficeComputer() {ComputerBuilder builder = new OfficeComputerBuilder();ComputerEngineer engineer = new ComputerEngineer(builder);// 构建办公电脑engineer.constructComputer();Computer computer = builder.getResult();// 验证办公电脑配置String computerStr = computer.toString();assertTrue(computerStr.contains("Intel i5-13600K"));assertTrue(computerStr.contains("16GB DDR4"));assertTrue(computerStr.contains("Intel UHD Graphics"));}@Testpublic void testOrderBuilder() {// 测试链式建造者Order order = new OrderBuilder().product("iPhone 15 Pro").address("上海市浦东新区").payment("微信支付").discount("满1000减100").amount(8999.00).build();assertEquals("iPhone 15 Pro", order.getProduct());assertEquals("微信支付", order.getPayment());assertTrue(order.isValid());}@Testpublic void testDifferentBuilders() {// 测试不同建造者产生不同结果ComputerBuilder gamingBuilder = new GamingComputerBuilder();ComputerBuilder officeBuilder = new OfficeComputerBuilder();ComputerEngineer engineer1 = new ComputerEngineer(gamingBuilder);ComputerEngineer engineer2 = new ComputerEngineer(officeBuilder);engineer1.constructComputer();engineer2.constructComputer();Computer gamingComputer = gamingBuilder.getResult();Computer officeComputer = officeBuilder.getResult();// 验证两台电脑配置不同assertNotEquals(gamingComputer.toString(), officeComputer.toString());}
}

8. 常见误区与反例

  • 误区1 :导演类(Director)过度复杂。
    如构建逻辑过多应拆分,避免导演类膨胀。
  • 误区2 :建造者接口设计不清晰。
    应保证步骤明确、职责单一。
  • 反例 :客户端直接操作产品部件。
    应通过建造者接口组装,避免高耦合。

9. 最佳实践

  1. 接口设计 :建造者接口要简洁,步骤明确,便于扩展和维护。
  2. 工厂与建造者结合 :复杂对象可结合工厂方法和建造者模式,提升灵活性。
  3. 链式调用 :对于参数较多的对象,推荐链式建造者,提升可读性。
  4. 异常与校验 :建造过程应妥善处理参数校验和异常。
  5. 文档和UML同步 :保持文档、UML和代码示例一致,便于团队协作。

10. 参考资料与延伸阅读

  • 《设计模式:可复用面向对象软件的基础》GoF
  • Effective Java(中文版)
  • https://refactoringguru.cn/design-patterns/builder
  • https://www.baeldung.com/java-builder-pattern

本文为设计模式系列第7篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83821.shtml

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

相关文章

HBuilder 发行Android(apk包)全流程指南

一、前言 小程序以其便捷性和轻量性受到越来越多开发者的青睐。HBuilder 作为一款强大的开发工具&#xff0c;为小程序开发提供了极大的便利。本文将详细介绍如何通过 HBuilder 完成小程序的开发与发行。 二、环境准备 1. 安装 HBuilder 访问 DCloud 官方网站&#xff0c;下…

React 18新特性介绍

React 18是React团队于2022年发布的一个重要版本&#xff0c;它引入了多项改进和新特性&#xff0c;在提升性能的同时也带来了一些使用上的变化。本文将全面介绍React 18的主要新特性&#xff0c;包括并发渲染、API更新、浏览器兼容性等重要内容&#xff0c;并通过代码示例说明…

设计模式——面向对象设计六大原则

摘要 本文详细介绍了设计模式中的六大基本原则&#xff0c;包括单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则、依赖倒置原则和合成复用原则。每个原则都通过定义、理解、示例三个部分进行阐述&#xff0c;旨在帮助开发者提高代码的可维护性和灵活性。通过具体代码…

使用 So-VITS-SVC 实现明星声音克隆与视频音轨替换实战全流程

本文展示如何使用开源项目 so-vits-svc 实现声音克隆与视频音轨替换流程&#xff0c;适用于 AI 音频工程、声音合成等学习场景。所述内容仅限技术交流&#xff0c;禁止用于非法用途。 一、项目背景 此项目采用 so-vits-svc 4.1 开源框架&#xff0c;实现了“用明星声音替换视频…

【学习记录】深入解析 AI 交互中的五大核心概念:Prompt、Agent、MCP、Function Calling 与 Tools

&#x1f4cc; 引言 随着大语言模型&#xff08;LLM&#xff09;的发展&#xff0c;AI 已经不再只是“回答问题”的工具&#xff0c;而是可以主动执行任务、调用外部资源、甚至构建完整工作流的智能系统。 为了更好地理解和使用这些能力&#xff0c;我们需要了解 AI 交互中几…

纹理压缩格式优化

🎯 Unity 项目纹理压缩格式优化终极指南 ——不同平台、不同手机型号,如何正确选择 🧩 什么是纹理压缩(Texture Compression)? Texture压缩 = 减小显存占用,提升加载速度,减轻GPU负担纹理是游戏中最大资源,占用50%+内存正确压缩:减少GPU Bandwidth,提高渲染性能错…

Docker轻松搭建Neo4j+APOC环境

Docker轻松搭建Neo4jAPOC环境 一、简介二、Docker部署neo4j三、Docker安装APOC插件四、删除数据库/切换数据库 一、简介 Neo4j 是一款高性能的 原生图数据库&#xff0c;采用 属性图模型 存储数据&#xff0c;支持 Cypher查询语言&#xff0c;适用于复杂关系数据的存储和分析。…

NGINX `ngx_stream_core_module` 模块概览

一、模块定位与功能 通用 TCP/UDP 代理 支持同时处理 TCP 和 UDP 流量&#xff0c;透明转发请求到后端服务器组&#xff08;upstream&#xff09;。可作为四层负载均衡&#xff0c;根据客户端 IP、权重、最少连接等策略将连接分发给后端。 预读&#xff08;preread&#xff09…

JVM类加载高阶实战:从双亲委派到弹性架构的设计进化

前言 作为Java开发者&#xff0c;我们都知道JVM的类加载机制遵循"双亲委派"原则。但在实际开发中&#xff0c;特别是在金融支付、插件化架构等场景下&#xff0c;严格遵循这个原则反而会成为系统扩展的桎梏。本文将带你深入理解双亲委派机制的本质&#xff0c;并分享…

MATLAB | 绘图复刻(十九)| 轻松拿捏 Nature Communications 绘图

hello这次真的是好久不见了&#xff0c;前段时间确实太忙&#xff0c;后台都忙到没时间看&#xff0c;对不住大家的热情&#xff0c;这期复刻两个 Nature Communications 绘图&#xff0c;主要都和弦图有关&#xff1a; 原图 1 复刻图 1 原图 2 复刻图 2 这次绘图使用我自己开…

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享

设计模式(代理设计模式)

代理模式解释清楚&#xff0c;所以如果想对一个类进行功能上增强而又不改变原来的代码情况下&#xff0c;那么只需要让这个类代理类就是我们的顺丰&#xff0c;对吧?并行增强就可以了。具体增强什么?在哪方面增强由代理类进行决定。 代码实现就是使用代理对象代理相关的逻辑…

Flask + ECharts+MYSQL全球贸易数字化大屏

核心功能: 全球贸易热力图:展示中国与各国的贸易关系强度 贸易指标卡片:实时显示贸易总额、投资额等关键指标 贸易伙伴排名:展示中国前10大贸易伙伴 贸易类型分布:展示各类商品的贸易占比 全球实时动态:滚动显示全球贸易、投资等实时事件 技术亮点: 使用WebSocket实现实…

wpf Behaviors库实现支持多选操作进行后台绑定数据的ListView

<ListView ItemsSource"{Binding SchemeItems}" SelectionMode"Extended" VerticalAlignment"Stretch" HorizontalAlignment"Stretch"><ListView.ContextMenu><ContextMenu><MenuItem Header"删除" …

50个JAVA常见代码大全:学完这篇从Java小白到架构师

50个JAVA常见代码大全&#xff1a;学完这篇从Java小白到架构师 Java&#xff0c;作为一门流行多年的编程语言&#xff0c;始终占据着软件开发领域的重要位置。无论是初学者还是经验丰富的程序员&#xff0c;掌握Java中常见的代码和概念都是至关重要的。本文将列出50个Java常用…

【Linux手册】冯诺依曼体系结构

目录 前言 五大组件 数据信号 存储器&#xff08;内存&#xff09;有必要吗 常见面试题 前言 冯诺依曼体系结构是当代计算机基本架构&#xff0c;冯诺依曼体系有五大组件&#xff0c;通过这五大组件直观的描述了计算机的工作原理&#xff1b;学习冯诺依曼体系可以让给我们更…

10_聚类

描述 聚类&#xff08;clustering&#xff09;是将数据集划分成组的任务&#xff0c;这些组叫作簇&#xff08;cluster&#xff09;。其目标是划分数据&#xff0c;使得一个簇内的数据点非常相似且不同簇内的数据点非常不同。与分类算法类似&#xff0c;聚类算法为每个数据点分…

【SSM】SpringBoot学习笔记1:SpringBoot快速入门

前言&#xff1a; 文章是系列学习笔记第9篇。基于黑马程序员课程完成&#xff0c;是笔者的学习笔记与心得总结&#xff0c;供自己和他人参考。笔记大部分是对黑马视频的归纳&#xff0c;少部分自己的理解&#xff0c;微量ai解释的内容&#xff08;ai部分会标出&#xff09;。 …

国产高性能pSRAM选型指南:CSS6404LS-LI 64Mb QSPI伪静态存储器

一、芯片基础特性 核心参数 容量 &#xff1a;64Mb&#xff08;8M 8bit&#xff09;电压 &#xff1a;单电源供电 2.7-3.6V &#xff08;兼容3.3V系统&#xff09;接口 &#xff1a;Quad-SPI&#xff08;QPI/SPI&#xff09;同步模式封装 &#xff1a; SOP-8L (150mil) &#…

Cilium动手实验室: 精通之旅---4.Cilium Gateway API - Lab

Cilium动手实验室: 精通之旅---4.Cilium Gateway API - Lab 1. 环境准备2. API 网关--HTTP2.1 部署应用2.2 部署网关2.3 HTTP路径匹配2.4 HTTP头匹配 3. API网关--HTTPS3.1 创建TLS证书和私钥3.2 部署HTTPS网关3.3 HTTPS请求测试 4. API网关--TLS 路由4.1 部署应用4.2 部署网关…