4、Java 建造者模式从入门到实战(后端必备)
Java 建造者模式从入门到实战(后端必备)
前言:建造者模式是Java后端开发中最常用的创建型设计模式之一,核心解决“复杂对象创建繁琐”的问题。无论是日常开发中的POJO构建、框架底层的API设计,还是面试中的高频提问,它都无处不在。本文从入门到实战,结合Java真实开发场景,带你吃透建造者模式,看完直接能用、能说、能面试。
一、为什么需要建造者模式?(痛点直击)
做Java开发,你一定遇到过这样的问题:
-
实体类参数太多(比如10+个字段),构造器冗长,可读性差,调用时容易传错参数顺序;
-
用setter方法赋值,代码冗余,且无法保证对象不可变(setter可随时修改属性);
-
多构造器重叠(重载),维护困难,新增参数时需要修改多个构造器;
-
复杂对象的创建和组装过程混乱,耦合度高,难以维护。
而建造者模式,就是为解决这些痛点而生——将复杂对象的创建和组装分离,通过“链式调用”一步步构建对象,兼顾优雅性和安全性。
二、建造者模式核心概念(极简理解)
建造者模式的核心思想:“搭积木”式构建对象。把复杂对象拆分成多个简单组件,分步骤构建,最后组装成完整对象。
标准建造者模式有4个核心角色(理论层面),但Java实际开发中,我们几乎不用这么复杂,重点掌握简化版即可:
-
Product(产品):需要构建的复杂对象(比如User、Order实体);
-
Builder(抽象建造者):定义构建产品的抽象方法(规范步骤);
-
ConcreteBuilder(具体建造者):实现抽象方法,完成具体组件的构建和组装;
-
Director(指挥者):控制构建流程,调用建造者的方法完成对象创建(实际开发中可省略,直接由Builder控制)。
重点:Java后端开发中,最常用的是“链式建造者”,省略抽象建造者和指挥者,直接在产品类中内置具体建造者,实现链式调用,简洁高效。
三、实战一:手写链式建造者(基础必备)
先手动实现一个链式建造者,理解其底层原理,后续用Lombok简化会更清晰。以常见的User实体为例,包含必选参数和可选参数:
/**
* 产品类:User(复杂对象)
* 特点:构造器私有,无setter,保证不可变
*/
public class User {
// 必选参数(必须传入)
private final Long id;
// 可选参数(可选择性设置)
private final String name;
private final Integer age;
private final String phone;
private final String address;
// 构造器私有:只能通过建造者创建对象
private User(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
// 内置建造者(核心)
public static class Builder {
// 必选参数(必须在构造器中传入)
private final Long id;
// 可选参数(默认值可省略,也可设置默认值)
private String name;
private Integer age;
private String phone;
private String address;
// 建造者构造器:传入必选参数
public Builder(Long id) {
this.id = id;
}
// 可选参数链式方法:返回Builder本身,实现链式调用
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(Integer age) {
this.age = age;
return this;
}
public Builder phone(String phone) {
this.phone = phone;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
// 构建产品:返回最终的User对象
public User build() {
// 可在此处添加参数校验(比如id不为null、age合法等)
if (id == null) {
throw new IllegalArgumentException("用户ID不能为空");
}
return new User(this);
}
}
// getter方法:只提供查询,不提供修改(保证不可变)
public Long getId() {
return id;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
}
使用方式(链式调用,优雅简洁)
public class BuilderTest {
public static void main(String[] args) {
// 1. 必选参数传入建造者,可选参数链式设置,最后build()创建对象
User user = new User.Builder(1001L)
.name("张三")
.age(25)
.phone("13800138000")
.address("北京市海淀区")
.build();
// 2. 可选参数可省略(灵活)
User user2 = new User.Builder(1002L)
.name("李四")
.build();
System.out.println(user.getName()); // 张三
System.out.println(user2.getAge()); // null(未设置)
}
}
手写建造者核心要点
-
产品类构造器私有,禁止外部直接new对象;
-
必选参数放入建造者的构造器,保证必须传入;
-
可选参数提供链式方法,返回Builder本身;
-
build()方法中可添加参数校验,保证对象合法性;
-
产品类只提供getter,不提供setter,保证对象不可变。
四、实战二:Lombok @Builder(Java后端最主流用法)
实际项目中,没人会手动写建造者(太繁琐),直接用Lombok的@Builder注解,一键生成链式建造者,代码量骤减。
1. 引入Lombok依赖(pom.xml)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. 注解使用(一行搞定建造者)
import lombok.Builder;
import lombok.Data;
/**
* 用Lombok @Builder生成建造者
* @Data:生成getter、setter、toString等(可选,根据需求添加)
* @Builder:生成链式建造者
*/
@Data
@Builder
public class User {
// 必选参数(无特殊设置,调用时必须传入)
private Long id;
// 可选参数
private String name;
private Integer age;
private String phone;
private String address;
}
3. 使用方式(和手写版完全一致)
public class LombokBuilderTest {
public static void main(String[] args) {
User user = User.builder()
.id(1001L)
.name("张三")
.age(25)
.phone("13800138000")
.build();
System.out.println(user);
}
}
Lombok @Builder 注意事项
-
@Builder会自动生成私有构造器、Builder内部类和链式方法;
-
如果需要必选参数强制传入,可结合@NonNull注解(比如@NonNull private Long id);
-
@Builder可与@Data、@NoArgsConstructor、@AllArgsConstructor搭配使用(注意冲突,建议用@Data即可);
-
IDEA需安装Lombok插件,否则会提示报错(插件市场搜索Lombok安装重启即可)。
五、实战三:框架中的建造者模式(面试必说)
建造者模式在Java主流框架中大量应用,面试时能说出1-2个,会显得你理解更深刻。
1. JDK自带:StringBuilder / StringBuffer
最基础、最常见的建造者模式应用,append()方法就是链式建造:
// StringBuilder的append()就是链式建造
StringBuilder sb = new StringBuilder();
sb.append("Java")
.append("建造者模式")
.append("实战");
String result = sb.toString();
2. MyBatis / MyBatis-Plus
查询条件构建、SQL构建,全是建造者模式的思想:
// MyBatis-Plus:LambdaQueryChainWrapper(链式查询)
List<User> userList = new LambdaQueryChainWrapper<>(userMapper)
.eq(User::getName, "张三")
.ge(User::getAge, 18)
.orderByDesc(User::getId)
.list();
// MyBatis:SqlSessionFactoryBuilder
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(inputStream);
3. Spring 框架
Spring中大量使用建造者模式构建复杂对象:
// BeanDefinitionBuilder:构建Bean定义
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
builder.addPropertyValue("id", 1001L)
.addPropertyValue("name", "张三");
BeanDefinition beanDefinition = builder.getBeanDefinition();
// MockMvc:测试接口时的链式构建
mockMvc.perform(MockMvcRequestBuilders.post("/user/login")
.param("username", "admin")
.param("password", "123456"))
.andExpect(status().isOk());
4. OkHttp 框架
HTTP请求构建,链式调用非常优雅:
// Request.Builder:构建HTTP请求
Request request = new Request.Builder()
.url("https://www.baidu.com")
.get()
.addHeader("Content-Type", "application/json")
.build();
六、建造者模式面试高频考点(必背)
1. 建造者模式的核心优势?
-
可读性强:链式调用,代码优雅,一眼能看出对象的构建过程;
-
灵活性高:可选参数可自由组合,无需创建多个构造器;
-
安全性高:可保证对象不可变(无setter),且能在build()中做参数校验;
-
解耦:将对象的创建和组装分离,降低耦合度,便于维护和扩展。
2. 建造者模式和工厂模式的区别?(高频)
核心区别:工厂模式关注“创建对象”,建造者模式关注“组装对象”。
-
工厂模式:直接返回一个完整的对象,不关心对象的组装过程;
-
建造者模式:分步骤构建对象,可灵活控制对象的各个组件,关注“怎么组装”。
举例:工厂模式直接给你一台完整的手机;建造者模式给你零件,一步步组装成手机,可选择不同的屏幕、电池。
3. 什么时候用建造者模式?
-
对象参数多(尤其是可选参数多),构造器冗长;
-
需要构建不可变对象(无setter);
-
复杂对象的创建和组装过程需要灵活控制;
-
希望代码更优雅、可读性更强(链式调用)。
七、总结(实战+面试双达标)
对于Java后端开发者来说,建造者模式不是“花里胡哨”的设计模式,而是日常开发必备的工具:
-
基础:理解链式建造者的原理,能手写简单版本;
-
实战:熟练使用Lombok @Builder,简化开发;
-
面试:能说出框架中的应用,区分建造者和工厂模式。
记住一句话:参数多、要优雅、需不可变,就用建造者模式。它能帮你解决构造器冗余、代码混乱的问题,让你的代码更具可读性和可维护性。
补充:常见问题解决
-
问题1:Lombok @Builder生成的对象,无法用无参构造器?
解决:添加@NoArgsConstructor,或用User.builder().build()创建空对象(需保证无必选参数)。 -
问题2:如何强制必选参数?
解决:结合@NonNull注解,或手写建造者(将必选参数放入建造者构造器)。 -
问题3:建造者模式和构造器、setter的区别?
解决:构造器适合参数少的场景;setter适合对象可修改的场景;建造者适合参数多、不可变、需优雅构建的场景。
更多推荐


所有评论(0)