建造者模式详解

发布于:2025-03-21 ⋅ 阅读:(24) ⋅ 点赞:(0)

以下是一个结合建造者模式解决实际开发问题的Java实现案例,包含参数校验、可选参数处理、不可变对象构建等场景需求,逐行注释说明:

场景描述

实现一个用户信息构建器,需满足:
必填参数:姓名(name)、身份证号(id)
可选参数:年龄(age)、地址(address)、电话(phone)
参数校验:身份证号必须为18位,年龄范围需合理
不可变对象:用户信息一旦创建不允许修改
构建过程友好:支持链式调用,明确参数设置顺序

实现:

/**
 * 用户信息类(不可变对象)
 */
public final class User {
    // 所有字段用final修饰确保不可变
    private final String name;      // 必填
    private final String id;       // 必填
    private final int age;         // 可选(默认-1表示未设置)
    private final String address;  // 可选(默认null)
    private final String phone;    // 可选(默认null)

    // 私有构造器,只能通过建造者创建实例
    private User(Builder builder) {
        this.name = builder.name;
        this.id = builder.id;
        this.age = builder.age;
        this.address = builder.address;
        this.phone = builder.phone;
    }

    /**
     * 静态内部建造者类
     */
    public static class Builder {
        // 必填参数
        private final String name;
        private final String id;

        // 可选参数(设置默认值)
        private int age = -1;       // -1表示未设置
        private String address = null;
        private String phone = null;

        /**
         * 构造方法(强制必填参数)
         * @param name 姓名(非空且长度>1)
         * @param id 身份证号(必须18位)
         */
        public Builder(String name, String id) {
            // 参数校验放在构造器入口
            if (name == null || name.trim().length() < 2) {
                throw new IllegalArgumentException("姓名至少2个字符");
            }
            if (id == null || id.length() != 18) {
                throw new IllegalArgumentException("身份证号必须为18位");
            }
            this.name = name;
            this.id = id;
        }

        /**
         * 设置年龄(可选)
         * @param age 必须≥0且≤150
         */
        public Builder age(int age) {
            if (age < 0 || age > 150) {
                throw new IllegalArgumentException("年龄不合法");
            }
            this.age = age;
            return this; // 返回this支持链式调用
        }

        /**
         * 设置地址(可选)
         */
        public Builder address(String address) {
            this.address = address;
            return this;
        }

        /**
         * 设置电话(可选)
         * @param phone 必须为11位数字
         */
        public Builder phone(String phone) {
            if (phone != null && !phone.matches("\\d{11}")) {
                throw new IllegalArgumentException("电话格式错误");
            }
            this.phone = phone;
            return this;
        }

        /**
         * 构建User对象(最终校验)
         */
        public User build() {
            // 集中处理跨参数校验逻辑(示例:如果填写电话必须填写地址)
            if (phone != null && address == null) {
                throw new IllegalStateException("填写电话必须同时填写地址");
            }
            return new User(this);
        }
    }

    // Getter方法(无Setter确保不可变)
    public String getName() { return name; }
    public String getId() { return id; }
    public int getAge() { return age; }
    public String getAddress() { return address; }
    public String getPhone() { return phone; }

    @Override
    public String toString() {
        return String.format("User[name=%s, id=%s, age=%d, address=%s, phone=%s]",
                name, id, age, address, phone);
    }

    // ------------------- 测试代码 -------------------
    public static void main(String[] args) {
        // 正确用法:链式调用+参数校验
        User user1 = new Builder("张三", "123456200001011234")
                .age(25)
                .address("北京市朝阳区")
                .phone("13800138000")
                .build();
        System.out.println(user1); 

        // 测试必填参数校验
        try {
            new Builder("李", "123"); // 姓名太短+身份证号长度错误
        } catch (IllegalArgumentException e) {
            System.out.println("参数校验捕获:" + e.getMessage());
        }

        // 测试跨参数校验
        try {
            new Builder("王五", "123456200001011234")
                    .phone("13800138000") // 未填地址
                    .build();
        } catch (IllegalStateException e) {
            System.out.println("跨参数校验捕获:" + e.getMessage());
        }
    }
}

扩展应用场景

配置对象构建

Config config = new Config.Builder()
    .setMaxThreads(50)
    .setTimeout(3000)
    .enableCache(true)
    .build();

复杂查询条件拼接

Query query = new Query.Builder()
    .select("name", "age")
    .from("users")
    .where("age > 18")
    .orderBy("name DESC")
    .build();

DTO对象组装

OrderDTO dto = new OrderDTO.Builder()
    .userId(1001)
    .addItem(item1)
    .addItem(item2)
    .setShippingAddress(address)
    .build();

一句话总结

建造者模式通过分步设置参数与校验,灵活构建复杂对象,提升代码可读性与可维护性。


网站公告

今日签到

点亮在社区的每一天
去签到