以下是一个结合建造者模式解决实际开发问题的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();
一句话总结
建造者模式通过分步设置参数与校验,灵活构建复杂对象,提升代码可读性与可维护性。