1 概述
1.1 简介
建造者模式(Builder Pattern)是一种创建型设计模式,其核心思想是将复杂对象的构建过程与对象的表示分离,使得同样的构建过程可以创建不同的表示。
复杂对象通常具有多个组成部分(属性或子对象),且构建过程涉及多步逻辑(如初始化、属性赋值、校验、组装等)。建造者模式通过拆分构建逻辑,由专门的"建造者"类负责分步构建对象,再由"指挥者"类(可选)协调建造流程,最终生成完整对象。
适用场景:
- 对象具有复杂的内部结构(包含多个成员变量、嵌套对象);
- 对象构建过程需要多步逻辑,且步骤顺序可能灵活调整;
- 需避免构造方法参数过多导致的" telescoping constructor "问题(构造器臃肿、可读性差);
- 需支持同一构建过程生成不同配置的对象实例。
1.2 主要角色
建造者模式包含5个核心角色,职责分工明确:
- 产品(Product):被构建的复杂对象,包含多个组成部分(属性或子对象),提供基本的属性设置和业务方法。
- 抽象建造者(Abstract Builder) :定义构建产品的抽象接口,包含构建产品各组成部分的方法(如
buildPartA()、buildPartB())和返回产品的方法(如getResult())。 - 具体建造者(Concrete Builder):实现抽象建造者接口,负责具体的构建逻辑(如给产品属性赋值、校验参数、组装子对象),不同的具体建造者可生成不同配置的产品。
- 指挥者(Director):负责协调建造流程,定义构建产品的步骤顺序(如先构建PartA,再构建PartB),调用具体建造者的方法完成对象构建(可选角色,简单场景下可省略,由客户端直接调用建造者)。
- 客户端(Client):创建具体建造者和指挥者(若有),通过指挥者或直接调用建造者完成对象构建,最终获取产品实例。
1.3 优点
- 解耦构建与表示:构建逻辑封装在建造者类中,产品的表示(属性配置)与构建过程分离,同一构建流程可生成不同产品。
- 简化对象创建:避免复杂对象的臃肿构造器,通过分步调用建造方法设置属性,可读性和易用性更高。
- 灵活控制构建过程:可通过指挥者调整构建步骤顺序,或通过不同的具体建造者生成不同配置的产品,扩展性强。
- 职责单一:产品类负责封装业务逻辑,建造者类负责构建流程,指挥者类负责协调步骤,符合单一职责原则。
- 便于参数校验:在建造者的构建方法中可对参数进行校验(如非空、范围校验),确保产品实例的合法性。
1.4 缺点
- 增加类复杂度:相比直接创建对象,需额外定义抽象建造者、具体建造者、指挥者等类,增加了系统的类数量和理解成本。
- 仅适用于复杂对象:若对象结构简单(仅少数属性),使用建造者模式会显得冗余,不如直接通过构造器或setter方法高效。
- 建造者与产品耦合度高:具体建造者需深入了解产品的内部结构(如属性、子对象),若产品结构修改,对应的建造者也需同步修改,维护成本较高。
- 灵活性有限:若产品的组成部分(属性)频繁变更,需频繁修改抽象建造者和具体建造者的接口/方法,扩展性受限于初始设计。
2 实现
2.1.1 类图(mermaid语法)
Product - partA: String - partB: String - partC: String +setPartA(a: String) +setPartB(b: String) +setPartC(c: String) +show() AbstractBuilder +abstract buildPartA() +abstract buildPartB() +abstract buildPartC() +abstract getResult() ConcreteBuilder1 - product: Product +ConcreteBuilder1() +buildPartA() +buildPartB() +buildPartC() +getResult() ConcreteBuilder2 - product: Product +ConcreteBuilder2() +buildPartA() +buildPartB() +buildPartC() +getResult() Director - builder: AbstractBuilder +Director(builder: AbstractBuilder) +construct()
2.3.2 示例代码
以下以"电脑组装"为例,实现建造者模式:
- 产品(Product):电脑(Computer),包含CPU、内存、硬盘、显卡等组成部分;
- 抽象建造者(AbstractBuilder):电脑建造者接口(ComputerBuilder);
- 具体建造者:游戏本建造者(GamingLaptopBuilder)、办公本建造者(OfficeLaptopBuilder);
- 指挥者(Director):电脑组装指挥者(ComputerAssembler),负责协调组装步骤。
1. 产品类(Product)
java
// 电脑产品类
public class Computer {
// 产品组成部分
private String cpu;
private String ram;
private String hardDisk;
private String graphicsCard;
private String keyboard;
// setter方法(建造者通过setter设置属性)
public void setCpu(String cpu) {
this.cpu = cpu;
}
public void setRam(String ram) {
this.ram = ram;
}
public void setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
}
public void setGraphicsCard(String graphicsCard) {
this.graphicsCard = graphicsCard;
}
public void setKeyboard(String keyboard) {
this.keyboard = keyboard;
}
// 展示电脑配置
public void showConfig() {
System.out.println("电脑配置:");
System.out.println("CPU:" + cpu);
System.out.println("内存:" + ram);
System.out.println("硬盘:" + hardDisk);
System.out.println("显卡:" + graphicsCard);
System.out.println("键盘:" + keyboard);
}
}
2. 抽象建造者(Abstract Builder)
java
// 电脑建造者抽象接口
public interface ComputerBuilder {
// 构建各组成部分
void buildCpu();
void buildRam();
void buildHardDisk();
void buildGraphicsCard();
void buildKeyboard();
// 返回构建完成的电脑产品
Computer getResult();
}
3. 具体建造者(Concrete Builder)
java
// 游戏本建造者(高性能配置)
public class GamingLaptopBuilder implements ComputerBuilder {
private Computer computer;
// 初始化产品实例
public GamingLaptopBuilder() {
this.computer = new Computer();
}
@Override
public void buildCpu() {
computer.setCpu("Intel i9-13900HX(高性能处理器)");
}
@Override
public void buildRam() {
computer.setRam("64GB DDR5 5600MHz(超大内存)");
}
@Override
public void buildHardDisk() {
computer.setHardDisk("2TB NVMe SSD(高速硬盘)");
}
@Override
public void buildGraphicsCard() {
computer.setGraphicsCard("NVIDIA RTX 4090(顶级独显)");
}
@Override
public void buildKeyboard() {
computer.setKeyboard("RGB机械键盘(全键无冲)");
}
@Override
public Computer getResult() {
return this.computer;
}
}
// 办公本建造者(轻薄节能配置)
public class OfficeLaptopBuilder implements ComputerBuilder {
private Computer computer;
public OfficeLaptopBuilder() {
this.computer = new Computer();
}
@Override
public void buildCpu() {
computer.setCpu("Intel i5-1340P(低功耗处理器)");
}
@Override
public void buildRam() {
computer.setRam("16GB DDR5 4800MHz(够用内存)");
}
@Override
public void buildHardDisk() {
computer.setHardDisk("512GB NVMe SSD(日常存储)");
}
@Override
public void buildGraphicsCard() {
computer.setGraphicsCard("Intel UHD Graphics(集成显卡)");
}
@Override
public void buildKeyboard() {
computer.setKeyboard("静音巧克力键盘(轻薄便携)");
}
@Override
public Computer getResult() {
return this.computer;
}
}
4. 指挥者(Director)
java
// 电脑组装指挥者(协调构建步骤)
public class ComputerAssembler {
private ComputerBuilder builder;
// 注入具体建造者
public ComputerAssembler(ComputerBuilder builder) {
this.builder = builder;
}
// 定义构建流程(步骤顺序固定,可灵活调整)
public void assembleComputer() {
builder.buildCpu(); // 第一步:装CPU
builder.buildRam(); // 第二步:装内存
builder.buildHardDisk();// 第三步:装硬盘
builder.buildGraphicsCard();// 第四步:装显卡
builder.buildKeyboard();// 第五步:装键盘
}
}
5. 客户端调用
java
public class Client {
public static void main(String[] args) {
// 1. 构建游戏本
ComputerBuilder gamingBuilder = new GamingLaptopBuilder();
ComputerAssembler gamingAssembler = new ComputerAssembler(gamingBuilder);
gamingAssembler.assembleComputer(); // 指挥者协调构建
Computer gamingLaptop = gamingBuilder.getResult();
System.out.println("=== 游戏本配置 ===");
gamingLaptop.showConfig();
System.out.println("\n" + "=".repeat(50) + "\n");
// 2. 构建办公本
ComputerBuilder officeBuilder = new OfficeLaptopBuilder();
ComputerAssembler officeAssembler = new ComputerAssembler(officeBuilder);
officeAssembler.assembleComputer();
Computer officeLaptop = officeBuilder.getResult();
System.out.println("=== 办公本配置 ===");
officeLaptop.showConfig();
}
}
输出结果
=== 游戏本配置 ===
电脑配置:
CPU:Intel i9-13900HX(高性能处理器)
内存:64GB DDR5 5600MHz(超大内存)
硬盘:2TB NVMe SSD(高速硬盘)
显卡:NVIDIA RTX 4090(顶级独显)
键盘:RGB机械键盘(全键无冲)
==================================================
=== 办公本配置 ===
电脑配置:
CPU:Intel i5-1340P(低功耗处理器)
内存:16GB DDR5 4800MHz(够用内存)
硬盘:512GB NVMe SSD(日常存储)
显卡:Intel UHD Graphics(集成显卡)
键盘:静音巧克力键盘(轻薄便携)
3 具体应用
3.1 应用场景1:HTTP请求构建(模拟OkHttp的Request.Builder)
背景
HTTP请求是典型的复杂对象,包含请求URL、请求方法(GET/POST)、请求头(Headers)、请求体(Body)、超时时间、拦截器等多个组成部分,且不同请求的配置差异较大(如GET请求无Body,POST请求需设置Content-Type)。
使用建造者模式可简化HTTP请求的构建过程,避免构造器参数臃肿,同时支持灵活配置请求参数。
实现示例
java
import java.util.HashMap;
import java.util.Map;
// 1. 产品类:HTTP请求对象
class HttpRequest {
private String url;
private String method; // GET/POST/PUT/DELETE
private Map<String, String> headers;
private String body;
private int timeout; // 超时时间(毫秒)
// 私有构造方法(仅允许Builder创建)
private HttpRequest(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers;
this.body = builder.body;
this.timeout = builder.timeout;
}
// getter方法(用于后续发送请求时获取参数)
public String getUrl() { return url; }
public String getMethod() { return method; }
public Map<String, String> getHeaders() { return headers; }
public String getBody() { return body; }
public int getTimeout() { return timeout; }
// 展示请求信息
public void showRequest() {
System.out.println("HTTP请求信息:");
System.out.println("Method:" + method);
System.out.println("URL:" + url);
System.out.println("Headers:" + headers);
System.out.println("Body:" + body);
System.out.println("Timeout:" + timeout + "ms");
}
// 2. 内部建造者类(省略抽象建造者和指挥者,简化设计)
public static class Builder {
private String url; // 必传参数
private String method = "GET"; // 默认GET方法
private Map<String, String> headers = new HashMap<>();
private String body;
private int timeout = 5000; // 默认超时5秒
// 构造器:必传参数(URL)
public Builder(String url) {
if (url == null || url.isEmpty()) {
throw new IllegalArgumentException("URL不能为空");
}
this.url = url;
}
// 可选配置:请求方法
public Builder method(String method) {
this.method = method.toUpperCase();
return this; // 链式调用
}
// 可选配置:添加请求头
public Builder addHeader(String key, String value) {
this.headers.put(key, value);
return this;
}
// 可选配置:请求体
public Builder body(String body) {
this.body = body;
return this;
}
// 可选配置:超时时间
public Builder timeout(int timeout) {
if (timeout < 0) {
throw new IllegalArgumentException("超时时间不能为负数");
}
this.timeout = timeout;
return this;
}
// 构建请求对象
public HttpRequest build() {
// 校验:POST请求必须有Body(示例校验逻辑)
if ("POST".equals(method) && (body == null || body.isEmpty())) {
throw new IllegalStateException("POST请求必须设置请求体");
}
return new HttpRequest(this);
}
}
}
// 3. 客户端调用(模拟发送HTTP请求)
public class HttpBuilderDemo {
public static void main(String[] args) {
// 构建GET请求(无Body,仅配置URL、超时、请求头)
HttpRequest getRequest = new HttpRequest.Builder("https://api.example.com/user/1")
.method("GET")
.addHeader("Accept", "application/json")
.timeout(3000)
.build();
System.out.println("=== GET请求 ===");
getRequest.showRequest();
System.out.println("\n" + "=".repeat(50) + "\n");
// 构建POST请求(需配置Body、Content-Type)
HttpRequest postRequest = new HttpRequest.Builder("https://api.example.com/user")
.method("POST")
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer token123")
.body("{\"name\":\"张三\",\"age\":25}")
.timeout(10000)
.build();
System.out.println("=== POST请求 ===");
postRequest.showRequest();
}
}
输出结果
=== GET请求 ===
HTTP请求信息:
Method:GET
URL:https://api.example.com/user/1
Headers:{Accept=application/json}
Body:null
Timeout:3000ms
==================================================
=== POST请求 ===
HTTP请求信息:
Method:POST
URL:https://api.example.com/user
Headers:{Content-Type=application/json, Authorization=Bearer token123}
Body:{"name":"张三","age":25}
Timeout:10000ms
核心价值
- 链式调用简化配置:通过
Builder的链式方法,清晰设置请求参数,可读性远高于多参数构造器; - 必传参数校验:通过Builder构造器强制传入必传参数(URL),避免遗漏;
- 灵活配置:支持按需设置请求方法、请求头、请求体等,默认值合理,减少重复代码;
- 参数合法性校验:在
build()方法中校验POST请求必须有Body等规则,确保请求对象合法。
3.2 应用场景2:文档生成器(Word/PDF文档构建)
背景
文档生成(如Word、PDF)是复杂对象构建场景:文档包含标题、正文、图片、表格、页眉页脚、格式设置(字体、颜色、对齐方式)等多个组成部分,且不同类型文档(如报告、简历、合同)的结构和格式差异较大。
使用建造者模式可拆分不同文档的构建逻辑,通过不同的具体建造者生成不同格式的文档,指挥者统一协调文档生成步骤(如先加标题、再加正文、最后加页眉页脚)。
实现示例
java
// 1. 产品类:文档对象
interface Document {
void addTitle(String title);
void addContent(String content);
void addImage(String imagePath);
void addFooter(String footer);
void showDocument(); // 展示文档内容(模拟生成后的预览)
}
// 具体产品:Word文档
class WordDocument implements Document {
private StringBuilder content = new StringBuilder();
@Override
public void addTitle(String title) {
content.append("[Word标题]:").append(title).append("\n");
}
@Override
public void addContent(String content) {
this.content.append("[Word正文]:").append(content).append("\n");
}
@Override
public void addImage(String imagePath) {
this.content.append("[Word图片]:").append(imagePath).append("(Word格式优化)\n");
}
@Override
public void addFooter(String footer) {
this.content.append("[Word页脚]:").append(footer).append("\n");
}
@Override
public void showDocument() {
System.out.println("=== Word文档内容 ===");
System.out.println(content.toString());
}
}
// 具体产品:PDF文档
class PdfDocument implements Document {
private StringBuilder content = new StringBuilder();
@Override
public void addTitle(String title) {
content.append("[PDF标题]:").append(title).append("(PDF加粗居中)\n");
}
@Override
public void addContent(String content) {
this.content.append("[PDF正文]:").append(content).append("(PDF段落格式)\n");
}
@Override
public void addImage(String imagePath) {
this.content.append("[PDF图片]:").append(imagePath).append("(PDF压缩优化)\n");
}
@Override
public void addFooter(String footer) {
this.content.append("[PDF页脚]:").append(footer).append("(PDF右对齐)\n");
}
@Override
public void showDocument() {
System.out.println("=== PDF文档内容 ===");
System.out.println(content.toString());
}
}
// 2. 抽象建造者:文档建造者
interface DocumentBuilder {
void buildTitle(String title);
void buildContent(String content);
void buildImage(String imagePath);
void buildFooter(String footer);
Document getDocument();
}
// 3. 具体建造者:Word文档建造者
class WordDocumentBuilder implements DocumentBuilder {
private WordDocument document = new WordDocument();
@Override
public void buildTitle(String title) {
document.addTitle(title);
}
@Override
public void buildContent(String content) {
document.addContent(content);
}
@Override
public void buildImage(String imagePath) {
document.addImage(imagePath);
}
@Override
public void buildFooter(String footer) {
document.addFooter(footer);
}
@Override
public Document getDocument() {
return document;
}
}
// 具体建造者:PDF文档建造者
class PdfDocumentBuilder implements DocumentBuilder {
private PdfDocument document = new PdfDocument();
@Override
public void buildTitle(String title) {
document.addTitle(title);
}
@Override
public void buildContent(String content) {
document.addContent(content);
}
@Override
public void buildImage(String imagePath) {
document.addImage(imagePath);
}
@Override
public void buildFooter(String footer) {
document.addFooter(footer);
}
@Override
public Document getDocument() {
return document;
}
}
// 4. 指挥者:文档生成指挥者
class DocumentDirector {
private DocumentBuilder builder;
public DocumentDirector(DocumentBuilder builder) {
this.builder = builder;
}
// 定义文档生成流程(固定步骤:标题→正文→图片→页脚)
public void generateDocument(String title, String content, String imagePath, String footer) {
builder.buildTitle(title);
builder.buildContent(content);
if (imagePath != null && !imagePath.isEmpty()) {
builder.buildImage(imagePath);
}
builder.buildFooter(footer);
}
}
// 5. 客户端调用
public class DocumentBuilderDemo {
public static void main(String[] args) {
// 生成Word文档
DocumentBuilder wordBuilder = new WordDocumentBuilder();
DocumentDirector wordDirector = new DocumentDirector(wordBuilder);
wordDirector.generateDocument(
"项目需求文档",
"本文档描述了XX项目的功能需求和技术规格...",
"D:/project/cover.png",
"版本:V1.0 | 日期:2025-12-01"
);
Document wordDoc = wordBuilder.getDocument();
wordDoc.showDocument();
System.out.println("\n" + "=".repeat(80) + "\n");
// 生成PDF文档
DocumentBuilder pdfBuilder = new PdfDocumentBuilder();
DocumentDirector pdfDirector = new DocumentDirector(pdfBuilder);
pdfDirector.generateDocument(
"个人简历",
"姓名:张三 | 职位:Java开发工程师 | 工作年限:3年...",
"D:/resume/photo.jpg",
"联系电话:138XXXX1234 | 邮箱:zhangsan@example.com"
);
Document pdfDoc = pdfBuilder.getDocument();
pdfDoc.showDocument();
}
}
输出结果
=== Word文档内容 ===
[Word标题]:项目需求文档
[Word正文]:本文档描述了XX项目的功能需求和技术规格...
[Word图片]:D:/project/cover.png(Word格式优化)
[Word页脚]:版本:V1.0 | 日期:2025-12-01
================================================================================
=== PDF文档内容 ===
[PDF标题]:个人简历(PDF加粗居中)
[PDF正文]:姓名:张三 | 职位:Java开发工程师 | 工作年限:3年...(PDF段落格式)
[PDF图片]:D:/resume/photo.jpg(PDF压缩优化)
[PDF页脚]:联系电话:138XXXX1234 | 邮箱:zhangsan@example.com(PDF右对齐)
核心价值
- 统一构建流程:指挥者
DocumentDirector定义了"标题→正文→图片→页脚"的固定流程,确保所有文档生成遵循统一规范; - 不同格式隔离:
WordDocumentBuilder和PdfDocumentBuilder分别实现不同文档的格式处理(如Word图片优化、PDF加粗居中),逻辑隔离,互不影响; - 扩展性强:若后续需要支持Excel文档,只需新增
ExcelDocument(产品)和ExcelDocumentBuilder(具体建造者),无需修改现有代码,符合开闭原则; - 简化客户端使用:客户端无需关注文档构建的细节步骤,只需传入内容参数,通过指挥者即可生成目标格式的文档。