建造者模式 (Builder)
📖 通俗理解
想象你去电脑城组装电脑:
- 你告诉店员:我要 i7 CPU、32G 内存、RTX 4090 显卡...
- 店员一步步帮你装好:装 CPU → 装内存 → 装显卡 → 装硬盘...
- 最后给你一台完整的电脑
建造者模式就是:将复杂对象的构建过程分解成多个简单步骤,一步步构建。
🎯 解决什么问题?
问题场景:创建一个复杂对象,构造函数有很多参数:
// 构造函数有10个参数,谁能记得住顺序?
Computer computer = new Computer("Intel i7", "NVIDIA RTX4090",
"32GB", "1TB SSD", "华硕", "750W", "Windows 11",
true, true, "黑色");
问题:
- 参数太多,容易传错
- 有些参数可选,有些必填,逻辑复杂
- 代码可读性差
建造者模式的解决方案:
// 链式调用,清晰易读
Computer computer = new Computer.Builder()
.cpu("Intel i7")
.gpu("NVIDIA RTX4090")
.memory("32GB")
.storage("1TB SSD")
.build();
🌰 生活中的例子
- 组装电脑:按步骤安装各个配件
- 建造房子:打地基 → 建框架 → 装修 → 交付
- 做汉堡:烤面包 → 放肉饼 → 加蔬菜 → 挤酱料
- 配置游戏角色:选职业 → 选技能 → 选装备 → 起名字
💻 Java 代码实现
方式一:经典建造者模式
第一步:定义产品类
/**
* 产品类:电脑
*/
public class Computer {
// 必选配置
private String cpu;
private String memory;
// 可选配置
private String gpu;
private String storage;
private String monitor;
private String keyboard;
private String mouse;
// 私有构造,只能通过 Builder 创建
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.memory = builder.memory;
this.gpu = builder.gpu;
this.storage = builder.storage;
this.monitor = builder.monitor;
this.keyboard = builder.keyboard;
this.mouse = builder.mouse;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", memory='" + memory + '\'' +
", gpu='" + gpu + '\'' +
", storage='" + storage + '\'' +
", monitor='" + monitor + '\'' +
", keyboard='" + keyboard + '\'' +
", mouse='" + mouse + '\'' +
'}';
}
// ========== 静态内部类 Builder ==========
public static class Builder {
// 必选参数
private String cpu;
private String memory;
// 可选参数,设置默认值
private String gpu = "集成显卡";
private String storage = "256GB SSD";
private String monitor = "无";
private String keyboard = "无";
private String mouse = "无";
// 必选参数通过构造方法传入
public Builder(String cpu, String memory) {
this.cpu = cpu;
this.memory = memory;
}
// 可选参数通过 setter 方法链式调用
public Builder gpu(String gpu) {
this.gpu = gpu;
return this;
}
public Builder storage(String storage) {
this.storage = storage;
return this;
}
public Builder monitor(String monitor) {
this.monitor = monitor;
return this;
}
public Builder keyboard(String keyboard) {
this.keyboard = keyboard;
return this;
}
public Builder mouse(String mouse) {
this.mouse = mouse;
return this;
}
// 构建最终对象
public Computer build() {
return new Computer(this);
}
}
}
第二步:使用建造者
public class Client {
public static void main(String[] args) {
// 基础配置电脑
Computer basicPC = new Computer.Builder("Intel i3", "8GB")
.build();
System.out.println("基础配置: " + basicPC);
// 游戏电脑
Computer gamingPC = new Computer.Builder("Intel i7", "32GB")
.gpu("NVIDIA RTX 4090")
.storage("2TB SSD")
.monitor("27寸 4K 显示器")
.keyboard("机械键盘")
.mouse("游戏鼠标")
.build();
System.out.println("游戏配置: " + gamingPC);
// 办公电脑
Computer officePC = new Computer.Builder("Intel i5", "16GB")
.storage("512GB SSD")
.monitor("24寸显示器")
.build();
System.out.println("办公配置: " + officePC);
}
}
输出结果:
基础配置: Computer{cpu='Intel i3', memory='8GB', gpu='集成显卡', storage='256GB SSD', monitor='无', keyboard='无', mouse='无'}
游戏配置: Computer{cpu='Intel i7', memory='32GB', gpu='NVIDIA RTX 4090', storage='2TB SSD', monitor='27寸 4K 显示器', keyboard='机械键盘', mouse='游戏鼠标'}
办公配置: Computer{cpu='Intel i5', memory='16GB', gpu='集成显卡', storage='512GB SSD', monitor='24寸显示器', keyboard='无', mouse='无'}
方式二:带 Director 的建造者模式
当有固定的构建流程时,可以使用 Director(指挥者)来封装构建步骤。
/**
* 产品:汉堡
*/
public class Burger {
private String bread;
private String meat;
private String vegetable;
private String sauce;
// getter 和 setter...
@Override
public String toString() {
return String.format("汉堡[%s + %s + %s + %s]",
bread, meat, vegetable, sauce);
}
}
/**
* 抽象建造者
*/
public abstract class BurgerBuilder {
protected Burger burger = new Burger();
public abstract void buildBread();
public abstract void buildMeat();
public abstract void buildVegetable();
public abstract void buildSauce();
public Burger getResult() {
return burger;
}
}
/**
* 具体建造者:鸡肉汉堡
*/
public class ChickenBurgerBuilder extends BurgerBuilder {
@Override
public void buildBread() {
burger.setBread("全麦面包");
}
@Override
public void buildMeat() {
burger.setMeat("鸡肉饼");
}
@Override
public void buildVegetable() {
burger.setVegetable("生菜+番茄");
}
@Override
public void buildSauce() {
burger.setSauce("蜂蜜芥末酱");
}
}
/**
* 具体建造者:牛肉汉堡
*/
public class BeefBurgerBuilder extends BurgerBuilder {
@Override
public void buildBread() {
burger.setBread("芝麻面包");
}
@Override
public void buildMeat() {
burger.setMeat("双层牛肉饼");
}
@Override
public void buildVegetable() {
burger.setVegetable("洋葱+酸黄瓜");
}
@Override
public void buildSauce() {
burger.setSauce("番茄酱+芝士");
}
}
/**
* 指挥者:定义构建步骤
*/
public class BurgerDirector {
private BurgerBuilder builder;
public BurgerDirector(BurgerBuilder builder) {
this.builder = builder;
}
// 指挥构建过程
public Burger construct() {
builder.buildBread();
builder.buildMeat();
builder.buildVegetable();
builder.buildSauce();
return builder.getResult();
}
}
使用方式:
public class Client {
public static void main(String[] args) {
// 做一个鸡肉汉堡
BurgerDirector director1 = new BurgerDirector(new ChickenBurgerBuilder());
Burger chickenBurger = director1.construct();
System.out.println("鸡肉汉堡: " + chickenBurger);
// 做一个牛肉汉堡
BurgerDirector director2 = new BurgerDirector(new BeefBurgerBuilder());
Burger beefBurger = director2.construct();
System.out.println("牛肉汉堡: " + beefBurger);
}
}
🔥 实战案例:HTTP 请求构建器
/**
* HTTP 请求对象
*/
public class HttpRequest {
private final String url;
private final String method;
private final Map<String, String> headers;
private final Map<String, String> params;
private final String body;
private final int timeout;
private HttpRequest(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers;
this.params = builder.params;
this.body = builder.body;
this.timeout = builder.timeout;
}
public void send() {
System.out.println("发送 HTTP 请求:");
System.out.println(" URL: " + url);
System.out.println(" Method: " + method);
System.out.println(" Headers: " + headers);
System.out.println(" Params: " + params);
System.out.println(" Body: " + body);
System.out.println(" Timeout: " + timeout + "ms");
}
public static class Builder {
private String url;
private String method = "GET";
private Map<String, String> headers = new HashMap<>();
private Map<String, String> params = new HashMap<>();
private String body;
private int timeout = 30000;
public Builder(String url) {
this.url = url;
}
public Builder method(String method) {
this.method = method;
return this;
}
public Builder get() {
this.method = "GET";
return this;
}
public Builder post() {
this.method = "POST";
return this;
}
public Builder header(String key, String value) {
this.headers.put(key, value);
return this;
}
public Builder param(String key, String value) {
this.params.put(key, value);
return this;
}
public Builder body(String body) {
this.body = body;
return this;
}
public Builder timeout(int timeout) {
this.timeout = timeout;
return this;
}
public HttpRequest build() {
// 可以在这里做参数校验
if (url == null || url.isEmpty()) {
throw new IllegalStateException("URL 不能为空");
}
return new HttpRequest(this);
}
}
}
使用方式:
public class Client {
public static void main(String[] args) {
// GET 请求
HttpRequest getRequest = new HttpRequest.Builder("https://api.example.com/users")
.get()
.header("Authorization", "Bearer token123")
.param("page", "1")
.param("size", "10")
.timeout(5000)
.build();
getRequest.send();
System.out.println("-------------------");
// POST 请求
HttpRequest postRequest = new HttpRequest.Builder("https://api.example.com/users")
.post()
.header("Content-Type", "application/json")
.body("{\"name\": \"张三\", \"age\": 25}")
.build();
postRequest.send();
}
}
✅ 适用场景
- 对象构造复杂:有很多配置参数
- 需要创建不同表示:同样的构建过程可以创建不同的对象
- 需要参数校验:在 build() 方法中统一校验
⚠️ 优缺点
优点:
- 链式调用,代码优雅
- 参数可选,灵活配置
- 可以在 build() 中做统一校验
- 创建的对象不可变(线程安全)
缺点:
- 代码量增加(需要额外的 Builder 类)
- 不适合简单对象
📚 框架中的应用
- StringBuilder:
new StringBuilder().append("a").append("b").toString() - Lombok @Builder:自动生成 Builder 代码
- OkHttp:
new Request.Builder().url(...).build() - Guava:
ImmutableList.builder().add(...).build()
小结
建造者模式的核心:把复杂对象的构建过程拆分成多个步骤,通过链式调用一步步构建。
简单记忆:像搭积木一样,一块一块往上堆。
👉 下一篇:原型模式
