什么是建造者模式
建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。简单来说,建造者模式允许您一步一步创建复杂对象,而不是一次性传入所有参数。
建造者模式特别适合那些需要多个步骤构建、有多个可选参数或者构建过程中需要遵循特定顺序的对象创建场景。
为什么需要建造者模式
假设我们有一个具有十多个属性的Computer
类,其中一些属性是必需的,而其他属性是可选的。使用传统的构造函数或JavaBean模式创建对象会带来以下问题:
- 伸缩构造函数问题:需要编写多个构造函数来处理不同的参数组合
- 可读性差:当参数较多时,构造函数调用难以理解
- 状态不一致:使用setter方法时,对象可能处于不完整状态
- 线程安全问题:构建过程中对象状态可能发生变化
建造者模式优雅地解决了这些问题。
建造者模式的核心实现
java
// 产品类
public class House {
// 必要参数
private final String foundation;
private final String structure;
private final String roof;
// 可选参数
private final String interior;
private final String exterior;
private final boolean hasGarage;
private final boolean hasSwimmingPool;
private final boolean hasGarden;
// 私有构造函数,只能通过Builder访问
private House(Builder builder) {
this.foundation = builder.foundation;
this.structure = builder.structure;
this.roof = builder.roof;
this.interior = builder.interior;
this.exterior = builder.exterior;
this.hasGarage = builder.hasGarage;
this.hasSwimmingPool = builder.hasSwimmingPool;
this.hasGarden = builder.hasGarden;
}
// Getters
public String getFoundation() { return foundation; }
public String getStructure() { return structure; }
public String getRoof() { return roof; }
public String getInterior() { return interior; }
public String getExterior() { return exterior; }
public boolean hasGarage() { return hasGarage; }
public boolean hasSwimmingPool() { return hasSwimmingPool; }
public boolean hasGarden() { return hasGarden; }
@Override
public String toString() {
return "House with " + foundation + " foundation, " + structure +
" structure, " + roof + " roof, " + interior + " interior, " +
exterior + " exterior. " +
(hasGarage ? "Has garage. " : "") +
(hasSwimmingPool ? "Has swimming pool. " : "") +
(hasGarden ? "Has garden." : "");
}
// 静态内部Builder类
public static class Builder {
// 必要参数
private final String foundation;
private final String structure;
private final String roof;
// 可选参数 - 设置默认值
private String interior = "普通装修";
private String exterior = "标准外墙";
private boolean hasGarage = false;
private boolean hasSwimmingPool = false;
private boolean hasGarden = false;
// 必要参数通过构造器强制传入
public Builder(String foundation, String structure, String roof) {
this.foundation = foundation;
this.structure = structure;
this.roof = roof;
}
// 可选参数通过具有链式调用的setter方法设置
public Builder interior(String interior) {
this.interior = interior;
return this;
}
public Builder exterior(String exterior) {
this.exterior = exterior;
return this;
}
public Builder garage(boolean hasGarage) {
this.hasGarage = hasGarage;
return this;
}
public Builder swimmingPool(boolean hasSwimmingPool) {
this.hasSwimmingPool = hasSwimmingPool;
return this;
}
public Builder garden(boolean hasGarden) {
this.hasGarden = hasGarden;
return this;
}
// build方法创建最终对象
public House build() {
// 可以在这里添加构建验证逻辑
return new House(this);
}
}
}
建造者模式的关键点
- 产品类:复杂对象,通常是不可变的
- Builder类:负责定义产品创建步骤的接口
- 链式调用:Builder方法返回Builder自身,支持流式API
- 最终构建方法 :完成产品创建的方法(如
build()
) - 参数分离:将必选参数和可选参数明确区分
使用建造者模式
java
public class BuilderPatternDemo {
public static void main(String[] args) {
// 使用Builder创建对象
House simpleHouse = new House.Builder(
"混凝土基础",
"砖墙结构",
"平顶屋顶")
.build();
System.out.println("简易房屋:");
System.out.println(simpleHouse);
// 使用Builder创建更复杂的对象,设置可选参数
House luxuryHouse = new House.Builder(
"深层钢筋混凝土基础",
"钢筋混凝土框架",
"坡顶屋顶")
.interior("豪华装修")
.exterior("大理石外墙")
.garage(true)
.swimmingPool(true)
.garden(true)
.build();
System.out.println("\n豪华房屋:");
System.out.println(luxuryHouse);
}
}
运行结果
vbnet
简易房屋:
House with 混凝土基础 foundation, 砖墙结构 structure, 平顶屋顶 roof, 普通装修 interior, 标准外墙 exterior.
豪华房屋:
House with 深层钢筋混凝土基础 foundation, 钢筋混凝土框架 structure, 坡顶屋顶 roof, 豪华装修 interior, 大理石外墙 exterior. Has garage. Has swimming pool. Has garden.
建造者模式的高级版本:带Director的建造者模式
在某些情况下,我们可能需要一个额外的Director
类来封装构建过程,特别是当构建过程复杂或需要被重用时。
java
// 抽象Builder接口
public interface HouseBuilder {
void buildFoundation();
void buildStructure();
void buildRoof();
void buildInterior();
void buildExterior();
void buildGarage();
void buildSwimmingPool();
void buildGarden();
House getResult();
}
// 具体Builder实现
public class StandardHouseBuilder implements HouseBuilder {
private String foundation;
private String structure;
private String roof;
private String interior;
private String exterior;
private boolean hasGarage;
private boolean hasSwimmingPool;
private boolean hasGarden;
@Override
public void buildFoundation() {
this.foundation = "标准混凝土基础";
}
@Override
public void buildStructure() {
this.structure = "砖混结构";
}
@Override
public void buildRoof() {
this.roof = "普通瓦片屋顶";
}
@Override
public void buildInterior() {
this.interior = "基础装修";
}
@Override
public void buildExterior() {
this.exterior = "普通外墙";
}
@Override
public void buildGarage() {
this.hasGarage = false;
}
@Override
public void buildSwimmingPool() {
this.hasSwimmingPool = false;
}
@Override
public void buildGarden() {
this.hasGarden = false;
}
@Override
public House getResult() {
return new House(foundation, structure, roof,
interior, exterior, hasGarage,
hasSwimmingPool, hasGarden);
}
}
// 另一个具体Builder实现
public class LuxuryHouseBuilder implements HouseBuilder {
private String foundation;
private String structure;
private String roof;
private String interior;
private String exterior;
private boolean hasGarage;
private boolean hasSwimmingPool;
private boolean hasGarden;
@Override
public void buildFoundation() {
this.foundation = "深层钢筋混凝土基础";
}
// 其他方法实现...
@Override
public House getResult() {
return new House(foundation, structure, roof,
interior, exterior, hasGarage,
hasSwimmingPool, hasGarden);
}
}
// Director类
public class HouseDirector {
private HouseBuilder builder;
public HouseDirector(HouseBuilder builder) {
this.builder = builder;
}
// 更换Builder
public void changeBuilder(HouseBuilder builder) {
this.builder = builder;
}
// 构建最小可居住房屋
public void constructMinimalHouse() {
builder.buildFoundation();
builder.buildStructure();
builder.buildRoof();
builder.buildInterior();
builder.buildExterior();
}
// 构建完整功能房屋
public void constructFullFeaturedHouse() {
builder.buildFoundation();
builder.buildStructure();
builder.buildRoof();
builder.buildInterior();
builder.buildExterior();
builder.buildGarage();
builder.buildSwimmingPool();
builder.buildGarden();
}
}
实际应用示例:流畅的API构建器
下面通过一个SQL查询构建器的例子来展示建造者模式在实际API设计中的应用:
java
// SQL查询构建器
public class SQLQueryBuilder {
private String table;
private List<String> columns = new ArrayList<>();
private List<String> conditions = new ArrayList<>();
private List<String> orderBy = new ArrayList<>();
private Integer limit;
private Integer offset;
public SQLQueryBuilder from(String table) {
this.table = table;
return this;
}
public SQLQueryBuilder select(String... columns) {
if (columns.length == 0) {
this.columns.add("*");
} else {
this.columns.addAll(Arrays.asList(columns));
}
return this;
}
public SQLQueryBuilder where(String condition) {
this.conditions.add(condition);
return this;
}
public SQLQueryBuilder orderBy(String column, boolean ascending) {
this.orderBy.add(column + (ascending ? " ASC" : " DESC"));
return this;
}
public SQLQueryBuilder limit(int limit) {
this.limit = limit;
return this;
}
public SQLQueryBuilder offset(int offset) {
this.offset = offset;
return this;
}
public String build() {
// 验证必要参数
if (table == null) {
throw new IllegalStateException("表名未指定");
}
StringBuilder query = new StringBuilder();
query.append("SELECT ");
// 添加列
if (columns.isEmpty()) {
query.append("*");
} else {
query.append(String.join(", ", columns));
}
// 添加表
query.append(" FROM ").append(table);
// 添加条件
if (!conditions.isEmpty()) {
query.append(" WHERE ");
query.append(String.join(" AND ", conditions));
}
// 添加排序
if (!orderBy.isEmpty()) {
query.append(" ORDER BY ");
query.append(String.join(", ", orderBy));
}
// 添加限制
if (limit != null) {
query.append(" LIMIT ").append(limit);
}
// 添加偏移
if (offset != null) {
query.append(" OFFSET ").append(offset);
}
return query.toString();
}
}
SQL构建器的使用示例
java
public class SQLBuilderDemo {
public static void main(String[] args) {
// 创建简单查询
String simpleQuery = new SQLQueryBuilder()
.from("users")
.select("id", "name", "email")
.build();
System.out.println("简单查询:");
System.out.println(simpleQuery);
// 创建复杂查询
String complexQuery = new SQLQueryBuilder()
.select("u.id", "u.name", "COUNT(o.id) as order_count")
.from("users u LEFT JOIN orders o ON u.id = o.user_id")
.where("u.status = 'active'")
.where("o.create_time > '2023-01-01'")
.orderBy("order_count", false)
.limit(10)
.offset(20)
.build();
System.out.println("\n复杂查询:");
System.out.println(complexQuery);
}
}
建造者模式的常见应用场景
- 文档生成器:构建HTML、PDF、Word文档
- 复杂对象构建:具有多个配置选项的对象
- 不可变对象创建:需要一次性设置所有属性的对象
- 流畅的API设计:提供链式调用的接口
- 配置构建:应用程序配置、网络请求配置等
- 测试数据构建:创建测试用例数据
- 复杂GUI创建:组装UI组件和布局
真实世界中的建造者模式应用
- Java中的StringBuilder/StringBuffer:字符串构建
- Lombok的@Builder注解:自动生成Builder代码
- Spring框架的UriComponentsBuilder:构建URI
- Apache Camel的RouteBuilder:构建路由规则
- Retrofit的RequestBuilder:构建HTTP请求
- OkHttp的Request.Builder:构建HTTP请求
建造者模式的优点
- 参数控制:分离必选参数和可选参数
- 构建过程封装:隐藏复杂构建过程的细节
- 可读性:创建对象的代码更具可读性
- 灵活性:同一构建过程可创建不同表示
- 不变性:可以创建不可变对象
- 参数验证:可在构建时检查参数有效性
建造者模式的缺点
- 代码量增加:需要创建额外的Builder类
- 复杂度:对于简单对象,可能过于复杂
- 性能开销:相比直接构造,略有性能损失
- 维护成本:当产品类变化时,需要同步修改Builder
建造者模式与工厂模式的区别
虽然建造者模式和工厂模式都是创建型模式,但它们有明显区别:
- 工厂模式 关注对象创建 的种类(what)
- 建造者模式 关注复杂对象 的构建过程(how)
工厂用于创建整个对象,而建造者关注对象各个部分的创建过程和装配顺序。
建造者模式变体:自引用泛型流畅接口
这种高级变体使用泛型保持链式调用时的类型安全:
java
public class Email {
// 邮件属性
private final String from;
private final List<String> to;
private final String subject;
private final String body;
private final List<String> attachments;
private Email(Builder builder) {
this.from = builder.from;
this.to = new ArrayList<>(builder.to);
this.subject = builder.subject;
this.body = builder.body;
this.attachments = new ArrayList<>(builder.attachments);
}
// 泛型Builder基类
public static class Builder<T extends Builder<T>> {
private String from;
private List<String> to = new ArrayList<>();
private String subject = "";
private String body = "";
private List<String> attachments = new ArrayList<>();
// 自引用泛型类型转换
@SuppressWarnings("unchecked")
protected final T self() {
return (T) this;
}
public T from(String from) {
this.from = from;
return self();
}
public T to(String address) {
this.to.add(address);
return self();
}
public T subject(String subject) {
this.subject = subject;
return self();
}
public T body(String body) {
this.body = body;
return self();
}
public T attachment(String attachment) {
this.attachments.add(attachment);
return self();
}
public Email build() {
validateRequiredFields();
return new Email(this);
}
private void validateRequiredFields() {
if (from == null || from.isEmpty()) {
throw new IllegalStateException("发件人不能为空");
}
if (to.isEmpty()) {
throw new IllegalStateException("收件人不能为空");
}
}
}
// 具体Builder
public static class EmailBuilder extends Builder<EmailBuilder> {
// 不需要额外代码,因为基类已实现了所有功能
}
// 便捷的静态工厂方法
public static EmailBuilder builder() {
return new EmailBuilder();
}
@Override
public String toString() {
return "Email{" +
"from='" + from + '\'' +
", to=" + to +
", subject='" + subject + '\'' +
", body='" + body + '\'' +
", attachments=" + attachments +
'}';
}
}
建造者模式最佳实践
- 使用场景选择:对象参数较多或构建过程复杂时使用
- 参数验证 :在
build()
方法中进行完整性校验 - 必选与可选分离:通过构造函数传入必选参数
- 不可变对象:建造者模式是创建不可变对象的好方法
- 链式API设计:返回this支持流畅接口
- 避免过早优化:简单对象不需要建造者模式
- 使用嵌套静态类:使Builder成为产品的静态内部类
建造者模式小结
建造者模式是一种强大的创建型设计模式,它通过分离复杂对象的构建过程与表示,使得创建过程更加灵活和可控。它特别适合于有多个参数选项的复杂对象创建,可以提高代码的可读性和可维护性。
在实际应用中,许多现代API和框架都采用了建造者模式的变体来提供流畅的接口。掌握这一模式有助于我们设计出更易用、更灵活的API,并解决对象创建中的复杂性问题。
无论是创建不可变对象,还是设计流畅的API,建造者模式都是一种值得掌握的重要设计模式。