一、建造者模式概述
建造者模式是一种创建型设计模式,旨在提供一种灵活的解决方案,用于创建复杂的对象,什么是复杂对象呢?简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件。它通过将对象的构建过程和表示分离,使得同样的构建过程可以创建不同的表示。
二、传统创建对象方式的痛点
-
构造方法参数过多,示例代码如下:
javaOrder order = new Order("202509250001", 9527, "2025-09-25 00:00:00", 100.00, "待支付", "微信支付");
大家可以看到,这个构造方法的参数太多了,写着写着可能你都分不清哪个参数对应哪个属性。可能你将"微信支付"赋值给了支付状态属性,将"待支付"赋值给了支付方式属性都没发现有问题,因为这两个字段都是字符串类型,编译器并不会报错。只要参数超过5个,调用者都会陷入参数地狱。
二、建造者模式的结构
建造者模式的四个角色:
- Product:产品类,最终要构建的复杂对象。
- Builder:抽象建造者,定义构建步骤的接口。
- ConcreteBuilder:具体建造者,实现抽象建造者的接口,实现构建步骤并返回产品。
- Direct:指挥者(可选),控制构建过程。
三、示例
很多系统中都会有下订单这个操作,这个订单表里面是包含了很多字段的,比如订单号、用户id、下单时间、订单总金额、订单状态、支付方式等多个可选部件,建造者模式可以灵活地进行组装,下面直接上代码。
传统版本
1.产品类
java
public class Order {
private String orderNum;
private int userId;
private Date orderTime;
private BigDecimal totalPrice;
private String status;
private String paymentMethod;
public String getOrderNum() {
return orderNum;
}
public void setOrderNum(String orderNum) {
this.orderNum = orderNum;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public LocalDateTime getOrderTime() {
return orderTime;
}
public void setOrderTime(Date orderTime) {
this.orderTime = orderTime;
}
public BigDecimal getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getPaymentMethod() {
return paymentMethod;
}
public void setPaymentMethod(String paymentMethod) {
this.paymentMethod = paymentMethod;
}
@Override
public String toString() {
return "Order{" +
"orderNum='" + orderNum + '\'' +
", userId=" + userId +
", orderTime=" + orderTime +
", totalPrice=" + totalPrice +
", status='" + status + '\'' +
", paymentMethod='" + paymentMethod + '\'' +
'}';
}
}
2.抽象建造者
java
public interface OrderBuilder {
void buildOrderNum(String orderNum);
void buildUserId(int userId);
void buildOrderTime(Date orderTime);
void buildTotalPrice(BigDecimal totalPrice);
void buildStatus(String status);
void buildPaymentMethod(String paymentMethod);
/**
* 返回完整对象
*/
Order build();
}
抽象建造者中还声明了一个得到产品建造后结果的方法build。
3.具体建造者
java
public class ConcreteOrderBuilder implements OrderBuilder{
private Order order = new Order();
@Override
public void buildOrderNum(String orderNum) {
order.setOrderNum(orderNum);
}
@Override
public void buildUserId(int userId) {
order.setUserId(userId);
}
@Override
public void buildOrderTime(Date orderTime) {
order.setOrderTime(orderTime);
}
@Override
public void buildTotalPrice(BigDecimal totalPrice) {
order.setTotalPrice(totalPrice);
}
@Override
public void buildStatus(String status) {
order.setStatus(status);
}
@Override
public void buildPaymentMethod(String paymentMethod) {
order.setPaymentMethod(paymentMethod);
}
public Order build() {
return order;
}
}
4.指挥者
java
public class Director {
private OrderBuilder orderBuilder;
public Director(OrderBuilder orderBuilder) {
this.orderBuilder = orderBuilder;
}
/**
* 构建并返回完整对象
*/
public Order construct(String orderNum, int userId, Date orderTime, BigDecimal totalPrice, String status, String paymentMethod) {
orderBuilder.buildOrderNum(orderNum);
orderBuilder.buildUserId(userId);
orderBuilder.buildOrderTime(orderTime);
orderBuilder.buildTotalPrice(totalPrice);
orderBuilder.buildStatus(status);
orderBuilder.buildPaymentMethod(paymentMethod);
return orderBuilder.build();
}
}
5.客户端
java
public class Client {
public static void main(String[] args) {
//使用指挥者
OrderBuilder builder = new ConcreteOrderBuilder();
Director director = new Director(builder);
Order order = director.construct("202509250001", 9527,new Date(), new BigDecimal(100), "待支付", "微信支付");
//或者直接使用具体建造者
OrderBuilder builder1 = new ConcreteOrderBuilder();
builder1.buildOrderNum("202509250001");
builder1.buildUserId(9527);
builder1.buildOrderTime(new Date());
builder1.buildTotalPrice(new BigDecimal(100));
builder1.buildStatus("待支付");
builder1.buildPaymentMethod("微信支付");
Order order1 = builder1.build();
}
}
链式调用版本
java
public class Order {
private String orderNum;
private int userId;
private Date orderTime;
private BigDecimal totalPrice;
private String status;
private String paymentMethod;
//私有化构造器,外部不能new,只能通过Builder创建
private Order(String orderNum, int userId, Date orderTime, BigDecimal totalPrice, String status, String paymentMethod) {
this.orderNum = orderNum;
this.userId = userId;
this.orderTime = orderTime;
this.totalPrice = totalPrice;
this.status = status;
this.paymentMethod = paymentMethod;
}
@Override
public String toString() {
return "Order{" +
"orderNum='" + orderNum + '\'' +
", userId=" + userId +
", orderTime=" + orderTime +
", totalPrice=" + totalPrice +
", status='" + status + '\'' +
", paymentMethod='" + paymentMethod + '\'' +
'}';
}
public static class Builder {
private String orderNum;
private int userId;
private Date orderTime;
private BigDecimal totalPrice;
private String status;
private String paymentMethod;
public Builder buildOrderNum(String orderNum) {
this.orderNum = orderNum;
return this;
}
public Builder buildUserId(int userId) {
this.userId = userId;
return this;
}
public Builder buildOrderTime(Date orderTime) {
this.orderTime = orderTime;
return this;
}
public Builder buildTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
return this;
}
public Builder buildStatus(String status) {
this.status = status;
return this;
}
public Builder buildPaymentMethod(String paymentMethod) {
this.paymentMethod = paymentMethod;
return this;
}
public Order build() {
//这里可以添加校验逻辑
if(status == null){
throw new IllegalStateException("订单状态不能为空");
}
return new Order(orderNum, userId, orderTime, totalPrice, status, paymentMethod);
}
}
}
建造者类
java
public class ConcreteOrderBuilder {
private Order order = new Order();
public ConcreteOrderBuilder buildOrderNum() {
order.setOrderNum("202509250001");
return this;
}
public ConcreteOrderBuilder buildUserId() {
order.setUserId(9527);
return this;
}
public ConcreteOrderBuilder buildOrderTime() {
order.setOrderTime(LocalDateTime.now());
return this;
}
public ConcreteOrderBuilder buildTotalPrice() {
order.setTotalPrice(new BigDecimal(100));
return this;
}
public ConcreteOrderBuilder buildStatus() {
order.setStatus("待支付");
return this;
}
public ConcreteOrderBuilder buildPaymentMethod() {
order.setPaymentMethod("微信支付");
return this;
}
public Order getResult() {
return order;
}
}
客户端
java
public class Client {
public static void main(String[] args) {
//使用链式调用来创建对象,链式调用提升了代码可读性。
Order order = new Order.Builder()
.buildOrderNum("202509250001")
.buildOrderTime(new Date())
.buildPaymentMethod("微信支付")
.buildStatus("1")
.buildTotalPrice(BigDecimal.valueOf(100.00))
.buildUserId(9527)
.build();
System.out.println(order);
}
}
两种版本对比:
通过传统版本中,Director指挥者类中的construct方法可以看到,这种方式比较适合构建过程固定的场景。而链式调用版本,通过返回this实现链式调用,适合构建过程灵活、需要动态配置的场景。
如果你的项目中有使用到Lombok,那么你应该知道它提供了一个@Builder注解,Lombok的@Builder注解通过自动生成构建者模式代码实现链式调用,其核心机制是为目标类创建内部静态Builder类,每个属性对应生成同名链式方法(返回Builder实例),最终通过build()方法完成对象构建。(Lombok在编译期修改AST,生成包含完整链式方法的静态内部类。)
总结
当你的实体类满足以下条件时,可以考虑使用建造者模式:
- 实体类中字段太多,比如超过5个。
- 存在参数校验逻辑,比如上述例子中的userId字段要求必填,可以在build方法中加入校验逻辑。