建造者模式(Builder Pattern)详解
一、建造者模式简介
建造者模式(Builder Pattern) 是一种 创建型设计模式(对象创建型模式),它将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建出不同的表示。
你可以这样理解:
“建造者模式就像搭积木,你可以用相同的步骤(如:打地基 → 盖墙 → 装屋顶)来建造不同的房子(别墅、公寓、仓库)。”
它特别适用于构造过程稳定但内部组成多变的复杂对象。
将客户端与包含多个部件的复杂对象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。
关注如何逐步创建一个复杂的对象,不同的建造者定义了不同的创建过程。
建造者模式包含以下4个角色:
Builder(抽象建造者)
ConcreteBuilder(具体建造者)
Product(产品)
Director(指挥者)
二、解决的问题类型
建造者模式主要用于解决以下问题:
- 对象构造过程复杂,参数众多,尤其是存在可选参数时,使用
new
或构造函数会变得难以维护。 - 需要创建的对象具有多种组合形式,但构建流程一致。
- 避免“伸缩构造器反模式”(Telescoping Constructor Pattern):即定义多个参数数量不同的构造函数。
三、使用场景
场景 | 示例 |
---|---|
创建复杂对象 | 如 StringBuilder 、Http请求对象 、SQL查询对象 |
配置对象初始化 | 如 OkHttpClient 、Retrofit 、ThreadPoolExecutor |
UI组件构建 | 如 Android 中的 AlertDialog.Builder |
领域模型构建 | 如订单、用户信息等含多个可选字段的对象 |
需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员变量。
需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。
隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
四、核心概念
- Product(产品类):要创建的复杂对象。
- Builder(抽象建造者):定义创建产品各个部件的抽象接口。
- ConcreteBuilder(具体建造者):实现 Builder 接口,提供具体构建逻辑。
- Director(指挥者):负责调用建造者对象的构建步骤,控制流程(可选,在Java中常被省略,由客户端直接调用)。
- Client(客户端):创建建造者对象并逐步设置参数,最终生成产品。
五、实际代码案例(Java)
我们以“电脑(Computer)”的组装为例,演示建造者模式的使用。
1. 定义产品类:Computer
// 电脑产品类
public class Computer {
private String cpu;
private String ram;
private String storage;
private String gpu;
private boolean hasBluetooth;
private boolean hasWifi;
// 私有构造函数,只能由 Builder 创建
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.storage = builder.storage;
this.gpu = builder.gpu;
this.hasBluetooth = builder.hasBluetooth;
this.hasWifi = builder.hasWifi;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", storage='" + storage + '\'' +
", gpu='" + gpu + '\'' +
", hasBluetooth=" + hasBluetooth +
", hasWifi=" + hasWifi +
'}';
}
// 静态内部类 Builder
public static class Builder {
// 必填参数
private String cpu;
private String ram;
private String storage;
// 可选参数(默认值)
private String gpu = "集成显卡";
private boolean hasBluetooth = false;
private boolean hasWifi = true;
// 构造函数:必填参数
public Builder(String cpu, String ram, String storage) {
this.cpu = cpu;
this.ram = ram;
this.storage = storage;
}
// 设置可选参数的方法(链式调用)
public Builder setGpu(String gpu) {
this.gpu = gpu;
return this;
}
public Builder setHasBluetooth(boolean hasBluetooth) {
this.hasBluetooth = hasBluetooth;
return this;
}
public Builder setHasWifi(boolean hasWifi) {
this.hasWifi = hasWifi;
return this;
}
// 构建最终对象
public Computer build() {
return new Computer(this);
}
}
}
2. 客户端测试类
public class Client {
public static void main(String[] args) {
// 场景1:组装一台游戏电脑
Computer gamingPC = new Computer.Builder("i7", "32GB", "1TB SSD")
.setGpu("RTX 4080")
.setHasBluetooth(true)
.setHasWifi(true)
.build();
System.out.println("🎮 游戏电脑配置:");
System.out.println(gamingPC);
System.out.println();
// 场景2:组装一台办公笔记本
Computer officeLaptop = new Computer.Builder("i5", "16GB", "512GB SSD")
.setGpu("集成显卡") // 可省略,默认就是集成显卡
.setHasBluetooth(true)
.setHasWifi(true)
.build();
System.out.println("💼 办公笔记本配置:");
System.out.println(officeLaptop);
System.out.println();
// 场景3:极简配置(只填必填项)
Computer basicPC = new Computer.Builder("i3", "8GB", "256GB SSD").build();
System.out.println("📦 基础电脑配置:");
System.out.println(basicPC);
}
}
输出结果:
🎮 游戏电脑配置:
Computer{cpu='i7', ram='32GB', storage='1TB SSD', gpu='RTX 4080', hasBluetooth=true, hasWifi=true}
💼 办公笔记本配置:
Computer{cpu='i5', ram='16GB', storage='512GB SSD', gpu='集成显卡', hasBluetooth=true, hasWifi=true}
📦 基础电脑配置:
Computer{cpu='i3', ram='8GB', storage='256GB SSD', gpu='集成显卡', hasBluetooth=false, hasWifi=true}
典型代码
典型的复杂对象类代码:
class Product
{
private string partA; //定义部件,部件可以是任意类型,包括值类型和引用类型
private string partB;
private string partC;
public string PartA
{
get { return partA; }
set { partA = value; }
}
public string PartB
{
get { return partB; }
set { partB = value; }
}
public string PartC
{
get { return partC; }
set { partC = value; }
}
}
典型的抽象建造者类代码:
abstract class Builder
{
//创建产品对象
protected Product product = new Product();
public abstract void BuildPartA();
public abstract void BuildPartB();
public abstract void BuildPartC();
//返回产品对象
public Product GetResult()
{
return product;
}
}
典型的具体建造者类代码:
class ConcreteBuilder1 : Builder
{
public override void BuildPartA()
{
product.PartA = "A1";
}
public override void BuildPartB()
{
product.PartB = "B1";
}
public override void BuildPartC()
{
product.PartC = "C1";
}
}
典型的指挥者类代码:
class Director
{
private Builder builder;
public Director(Builder builder)
{
this.builder = builder;
}
public void SetBuilder(Builder builder)
{
this.builder = builder;
}
//产品构建与组装方法
public Product Construct()
{
builder.BuildPartA();
builder.BuildPartB();
builder.BuildPartC();
return builder.GetResult();
}
}
客户类代码片段:
……
Builder builder = new ConcreteBuilder1(); //可通过配置文件实现
Director director = new Director(builder);
Product product = director.Construct();
……
其他案例
- 某游戏软件公司决定开发一款基于角色扮演的多人在线网络游戏,玩家可以在游戏中扮演虚拟世界中的一个特定角色,角色根据不同的游戏情节和统计数据(例如力量、魔法、技能等)具有不同的能力,角色也会随着不断升级而拥有更加强大的能力。
作为该游戏的一个重要组成部分,需要对游戏角色进行设计,而且随着该游戏的升级将不断增加新的角色。通过分析发现,游戏角色是一个复杂对象,它包含性别、面容等多个组成部分,不同类型的游戏角色,其性别、面容、服装、发型等外部特性都有所差异,例如“天使”拥有美丽的面容和披肩的长发,并身穿一袭白裙;而“恶魔”极其丑陋,留着光头并穿一件刺眼的黑衣。
无论是何种造型的游戏角色,它的创建步骤都大同小异,都需要逐步创建其组成部分,再将各组成部分装配成一个完整的游戏角色。现使用建造者模式来实现游戏角色的创建。
2. KFC套餐
建造者模式可以用于描述KFC如何创建套餐:套餐是一个复杂对象,它一般包含主食(如汉堡、鸡肉卷等)和饮料(如果汁、可乐等)等组成部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客。
六、优缺点分析
优点 | 描述 |
---|---|
✅ 代码可读性强 | 链式调用清晰表达对象构建意图 |
✅ 灵活性高 | 可自由组合可选参数,无需重载多个构造函数 |
✅ 封装性好 | 产品类构造函数私有,对象一旦创建不可变(可实现不可变对象) |
✅ 符合单一职责和开闭原则 | 构建逻辑集中在 Builder 中,易于扩展 |
缺点 | 描述 |
---|---|
❌ 代码量增加 | 需要额外编写 Builder 类,类结构变复杂 |
❌ 适合属性较多的场景 | 如果对象属性很少,使用 Builder 反而显得繁琐 |
❌ 构建过程与表示耦合 | 虽然流程解耦,但 Builder 仍与 Product 类紧密关联 |
七、与工厂模式对比
对比点 | 建造者模式 | 工厂模式 |
---|---|---|
目的 | 构建复杂对象,强调构建过程 | 创建对象,强调创建结果 |
适用对象 | 内部结构复杂、参数多的对象 | 结构相对简单的对象 |
使用方式 | 分步设置参数,最后 build() |
一次性传参创建 |
典型应用 | StringBuilder , AlertDialog.Builder |
Calendar.getInstance() |
八、最终小结
建造者模式是一种非常实用且优雅的设计模式,特别适合用于创建参数多、有必填/可选字段、构造过程复杂的对象。它通过链式调用的方式,让对象的创建过程变得直观、清晰、易于维护。
在设计 API、构建配置类、处理复杂 DTO 或领域模型时,建造者模式是一个非常值得掌握的工具。许多主流框架(如 Lombok 的 @Builder
注解)也提供了对建造者模式的便捷支持。
📌 一句话总结:
建造者模式就像“定制套餐”,你可以一步步选择想要的配置,最后“下单”生成一个完整的对象。
✅ 推荐使用场景:
- 类的构造函数参数超过 4 个;
- 参数中包含多个可选字段;
- 需要保证对象创建过程的顺序或一致性;
- 希望提升代码的可读性和可维护性。
💡 小贴士:可以使用 Lombok 的
@Builder
注解自动生成 Builder 代码,减少样板代码。
@Builder
public class User {
private String name;
private int age;
private String email;
private boolean isActive;
}
// 使用:User user = User.builder().name("Tom").age(25).build();
以上部分内容由AI大模型生成,注意识别!