二十三种设计模式(五)--建造者模式

建造者模式

建造者模式解决的是构建大型复杂的类对象的问题.

当我们定义了一个简单的类, 构造函数非常简单, 直接new即可

但是当构建参数非常多, 比如有几十上百个, 且并不是所有参数都能用得到, 我们实际用到的仅仅是将某一部分参数初始化的类对象, 此时这个构建的过程将会非常的复杂繁琐

为了解决这种通过不同的参数组合实例化不同的类的问题, 就有了建造者模式

建造者模式的实现方式非常多, 但核心思想是将
XX obj = new XXClass(param1, param2, ... ...)

这个实例化过程拆解为:
XX obj = new Builder().a().b().build()

这样使用一个构建器创建实例的过程

建造者模式本质上就是把"对象的构建过程"从"对象本身"拆出来,由一个 Builder 专门负责构建,再由 build() 返回最终对象

把构造函数拆成一步步可读、可控、可组合的链式调用。

以下是一个最精简的建造者模式实现:

java 复制代码
public class BuilderMode {
    public static void main(String[] args) {
        Product product1 = new Product.Builder().b(5).build();
        product1.run();

        Product product2 = new Product.Builder().b(10).c(15).build();
        product2.run();
    }
}

class Product {
    private int a = 12; // 默认固定参数
    private int b;
    private int c;

    public void run() {
        System.out.print("Product a = " + a);
        if (b != 0) {
            System.out.print(" b = " + b);
        }
        if (c != 0) {
            System.out.print(" c = " + c);
        }
        System.out.println("");
    }

    // ***构建器***
    // 构建器采用内部类的方式实现
    // 这样可以将封装性做的很好, 避免Product类对外暴露属性
    public static class Builder {
        int b = 0;
        int c = 0;

        Builder b(int b) {
            this.b = b;
            return this;
        }

        Builder c(int c) {
            this.c = c;
            return this;
        }

        Product build() {
            // 参数合法性验证及异常处理
            // 处理异常过程省略

            // 构建最终合法可运行的对象
            Product product = new Product();
            product.b = b;
            product.c = c;
            return product;
        }
    }
}

运行结果:

复制代码
Product a = 12 b = 5
Product a = 12 b = 10 c = 15

下面是一个符合 Effective Java 推荐风格、贴近生产环境的建造者模式实现,涵盖空值校验、不可变性、链式调用、默认值、Builder 内部类、流畅 API 等核心特性的建造者模式类实现:

java 复制代码
final class User {
    // 核心字段(不可变 + 私有final)
    private final Long id;                // 必填:用户ID
    private final String username;        // 必填:用户名
    private final String email;           // 必填:邮箱
    private final Integer age;            // 可选:年龄(默认18)
    private final String phone;           // 可选:手机号(默认null)
    private final List<String> roles;     // 可选:角色列表(可变类型,需防御性拷贝)
    private final LocalDateTime createTime; // 可选:创建时间(默认当前时间)

    // 私有构造器:仅内部Builder可调用
    private User(Builder builder) {
        // 1. 必填参数校验(Effective Java强调:尽早校验参数)
        this.id = Objects.requireNonNull(builder.id, "用户ID(id)不能为空");
        this.username = Objects.requireNonNull(builder.username, "用户名(username)不能为空");
        this.email = Objects.requireNonNull(builder.email, "邮箱(email)不能为空");

        // 2. 可选参数(带默认值)
        this.age = builder.age != null ? builder.age : 18;
        this.phone = builder.phone;
        this.createTime = builder.createTime != null ? builder.createTime : LocalDateTime.now();

        // 3. 可变类型防御性拷贝(避免外部修改内部状态)
        this.roles = builder.roles != null
                ? Collections.unmodifiableList(new ArrayList<>(builder.roles)) // 不可变列表
                : Collections.emptyList();
    }

    // 静态内部Builder类(Effective Java推荐:静态内部类形式)
    public static class Builder {
        // 与User完全一致的字段(非final,用于临时存储)
        private Long id;
        private String username;
        private String email;
        private Integer age;
        private String phone;
        private List<String> roles;
        private LocalDateTime createTime;

        // 链式setter:返回Builder本身,支持流畅调用
        public Builder id(Long id) {
            this.id = id;
            return this;
        }

        public Builder username(String username) {
            this.username = username;
            return this;
        }

        public Builder email(String email) {
            this.email = email;
            return this;
        }

        public Builder age(Integer age) {
            // 字段合法性校验(非空+业务规则)
            if (age != null && (age < 0 || age > 150)) {
                throw new IllegalArgumentException("年龄(age)必须在0-150之间");
            }
            this.age = age;
            return this;
        }

        public Builder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public Builder roles(List<String> roles) {
            this.roles = roles;
            return this;
        }

        public Builder createTime(LocalDateTime createTime) {
            this.createTime = createTime;
            return this;
        }

        // 核心build方法:创建并返回不可变User对象
        public User build() {
            return new User(this);
        }
    }

    // 所有字段的getter(无setter,保证不可变性)
    public Long getId() {
        return id;
    }

    public String getUsername() {
        return username;
    }

    public String getEmail() {
        return email;
    }

    public Integer getAge() {
        return age;
    }

    public String getPhone() {
        return phone;
    }

    // 返回不可变视图,防止外部修改
    public List<String> getRoles() {
        return roles;
    }

    public LocalDateTime getCreateTime() {
        return createTime;
    }

    // 重写equals/hashCode(生产环境必备)
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) &&
                Objects.equals(username, user.username) &&
                Objects.equals(email, user.email) &&
                Objects.equals(age, user.age) &&
                Objects.equals(phone, user.phone) &&
                Objects.equals(roles, user.roles) &&
                Objects.equals(createTime, user.createTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username, email, age, phone, roles, createTime);
    }

    // 重写toString(调试/日志必备)
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                ", phone='" + phone + '\'' +
                ", roles=" + roles +
                ", createTime=" + createTime +
                '}';
    }
}
  1. 参数验证分布在builder的每个字段设置时, 便于及时发现问题
  2. User类的所有属性都是final private权限, 只能通过内部构造器赋值
  3. 在build阶段校验参数非空等业务逻辑, 保证最终生成的对象正确可运行
  4. 构造器对默认值进行处理, 保证对象合法可用
  5. 对可变类型(如 List、Date)做拷贝,避免外部修改

测试:

java 复制代码
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Collections;
import java.util.ArrayList;

public class BuilderMode {
    public static void main(String[] args) {
        // 1. 构建完整参数的User
        User fullUser = new User.Builder()
                .id(1001L)
                .username("zhangsan")
                .email("zhangsan@example.com")
                .age(28)
                .phone("13800138000")
                .roles(List.of("admin", "user"))
                .createTime(LocalDateTime.of(2025, 1, 1, 10, 0))
                .build();
        System.out.println("完整参数User: " + fullUser);

        // 2. 构建仅必填参数的User(使用默认值)
        User minimalUser = new User.Builder()
                .id(1002L)
                .username("lisi")
                .email("lisi@example.com")
                .build();
        System.out.println("仅必填参数User: " + minimalUser);

        // 3. 测试参数校验(年龄非法)
        try {
            new User.Builder()
                    .id(1003L)
                    .username("wangwu")
                    .email("wangwu@example.com")
                    .age(200) // 非法年龄
                    .build();
        } catch (IllegalArgumentException e) {
            System.out.println("参数校验生效: " + e.getMessage());
        }

        // 4. 测试不可变性(尝试修改roles)
        try {
            fullUser.getRoles().add("guest"); // 不可变列表会抛异常
        } catch (UnsupportedOperationException e) {
            System.out.println("不可变性校验生效: " + e.getMessage());
        }
    }
}

运行结果:

复制代码
完整参数User: User{id=1001, username='zhangsan', email='zhangsan@example.com', age=28, phone='13800138000', roles=[admin, user], createTime=2025-01-01T10:00}
仅必填参数User: User{id=1002, username='lisi', email='lisi@example.com', age=18, phone='null', roles=[], createTime=2025-11-30T13:14:48.996069700}
参数校验生效: 年龄(age)必须在0-150之间
不可变性校验生效: null
关于GoF经典的建造和模式

经典建造者模式有如下几个角色组成:

Builder 抽象接口, 用来制定构建器的标准接口, 当有多个构建器时才会用到

ConcreteBuilder 构建器的具体实现, 生成实际的产品对象

Director 指挥家, 用来固定构建器的构建流程

Product 产品类, 包含最终所有的属性和方法, 但是只能由构建器实例化, 外部不能实例化

Client 调用端, 先获取构造器实例, 然后通过构造器创建产品实例对象.

经典建造者模式在实际生产过程中很少用到, 不再举例.

相关推荐
4***g8941 小时前
Java进阶-SpringCloud设计模式-工厂模式的设计与详解
java·spring cloud·设计模式
北郭guo1 小时前
Java设计模式 【理论+代码实现】 让你从小白到大佬的蜕变
java·开发语言·设计模式
计算机徐师兄1 小时前
Java基于微信小程序的贝壳活动助手【附源码、文档说明】
java·微信小程序·贝壳活动助手·贝壳活动助手小程序·贝壳活动助手微信小程序·java贝壳活动助手小程序·java贝壳活动助手微信小程序
Gavin在路上1 小时前
架构设计之COLA架构
java·数据库·架构
MediaTea1 小时前
Python 库手册:gc 垃圾回收
java·开发语言·jvm·python·算法
碎像1 小时前
阿里云 ARMS 应用实时监控服务
java·阿里云·云计算
l***91471 小时前
常见的 Spring 项目目录结构
java·后端·spring
j***12151 小时前
java进阶1——JVM
java·开发语言·jvm
f***R82 小时前
HeidiSQL导入与导出数据
java