说说建造者模式

一、建造者模式概述

建造者模式是一种创建型设计模式,旨在提供一种灵活的解决方案,用于创建复杂的对象,什么是复杂对象呢?简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件。它通过将对象的构建过程和表示分离,使得同样的构建过程可以创建不同的表示。

二、传统创建对象方式的痛点

  1. 构造方法参数过多,示例代码如下:

    java 复制代码
    Order order = new Order("202509250001", 9527, "2025-09-25 00:00:00", 100.00, "待支付", "微信支付");

    大家可以看到,这个构造方法的参数太多了,写着写着可能你都分不清哪个参数对应哪个属性。可能你将"微信支付"赋值给了支付状态属性,将"待支付"赋值给了支付方式属性都没发现有问题,因为这两个字段都是字符串类型,编译器并不会报错。只要参数超过5个,调用者都会陷入参数地狱。

二、建造者模式的结构

建造者模式的四个角色:

  1. Product:产品类,最终要构建的复杂对象。
  2. Builder:抽象建造者,定义构建步骤的接口。
  3. ConcreteBuilder:具体建造者,实现抽象建造者的接口,实现构建步骤并返回产品。
  4. 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,生成包含完整链式方法的静态内部类。)

总结

当你的实体类满足以下条件时,可以考虑使用建造者模式:

  1. 实体类中字段太多,比如超过5个。
  2. 存在参数校验逻辑,比如上述例子中的userId字段要求必填,可以在build方法中加入校验逻辑。
相关推荐
無限進步D3 小时前
Java 运行原理
java·开发语言·入门
難釋懷3 小时前
安装Canal
java
是苏浙3 小时前
JDK17新增特性
java·开发语言
不光头强3 小时前
spring cloud知识总结
后端·spring·spring cloud
GetcharZp6 小时前
告别 Python 依赖!用 LangChainGo 打造高性能大模型应用,Go 程序员必看!
后端
阿里加多7 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
likerhood7 小时前
java中`==`和`.equals()`区别
java·开发语言·python
小小李程序员7 小时前
Langchain4j工具调用获取不到ThreadLocal
java·后端·ai