云计算百科
云计算领域专业知识百科平台

大白话说Java设计模式-09-建造者模式(源码剖析篇)

大白话说Java设计模式-09-建造者模式(源码剖析篇):JDK / Spring / MyBatis 中的建造者实现

📌 一句话本质:建造者在源码里不是"教科书式"的 Director + Builder,而是"链式调用 + 自动校验"的简化版。

🏷️ 标签:建造者模式 / JDK StringBuilder / Spring UriComponentsBuilder / MyBatis   🎯 适合:中高级后端 / 想读懂主流框架源码的工程师


目录

  • 一、为什么读建造者源码?一张地图先看清
  • 二、JDK 源码剖析:3 个经典建造者实现
  • 三、Spring / MyBatis 源码剖析:URL 与 SQL 建造者
  • 四、为什么框架作者这么设计?
  • 五、借鉴到我们项目:3 个"抄作业"实践
  • 六、本篇小结 + 下一模式预告

一、为什么读建造者源码?一张地图先看清

建造者模式在源码里出现的频率比抽象工厂高得多——因为"复杂对象分步构造"是个普遍需求。

源码地图:

类别框架 / 中间件建造者类复杂对象
JDK java.lang StringBuilder String
JDK java.lang StringBuffer String(线程安全)
JDK java.util.stream Stream.Builder Stream
JDK java.nio ByteBuffer 字节缓冲区
JDK java.util Locale.Builder Locale
Spring Spring Web UriComponentsBuilder URI
Spring Spring Web HttpHeaders HTTP 头
MyBatis MyBatis SqlSessionFactoryBuilder SqlSessionFactory
Lombok Lombok @Builder 注解 任意类
Guava Guava ImmutableList.builder() ImmutableList

我们按"JDK → Spring/MyBatis"的顺序来剖析。


二、JDK 源码剖析:3 个经典建造者实现

2.1 StringBuilder —— 字符串拼接的"链式建造者"

源码位置:

  • OpenJDK 17
  • src/java.base/share/classes/java/lang/StringBuilder.java

核心字段:

public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence {

/**
* 默认容量
*/

static final int DEFAULT_CAPACITY = 16;
}

核心方法(简化版):

/**
* ✅ 链式 append:每一步都返回 this
*/

@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}

@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}

@Override
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}

/**
* ✅ 工厂方法:build 出最终 String
*/

@Override
public String toString() {
// 创建新 String
return new String(value, 0, count);
}

为什么 StringBuilder 是"建造者"?

  • 分步构造:append() 一次又一次地"装部件"
  • 链式调用:每个 append 都返回 this
  • 不可变结果:toString() 产出不可变的 String
  • 半成品支持:StringBuilder 本身就是半成品
  • 完整流程:

    StringBuilder builder = new StringBuilder();
    ↓ append("Hello")
    builder = "Hello"
    ↓ append(" ")
    builder = "Hello "
    ↓ append("World")
    builder = "Hello World"
    ↓ toString()
    result = "Hello World" (新 String 对象)

    为什么 StringBuilder 是"链式"而不是"分步赋值"?

    因为字符串构造是高频操作,需要极致的简洁。链式调用比"分步 + build()"快 50%。

    2.2 Stream.Builder —— 流式 API 的"建造者"

    源码位置:

    • OpenJDK 17
    • src/java.base/share/classes/java/util/stream/Stream.java

    核心源码:

    public interface Stream<T> extends BaseStream<T, Stream<T>> {

    /**
    * ✅ 内部 Builder 接口
    */

    interface Builder<T> extends Consumer<T> {
    @Override
    Builder<T> accept(T t); // 添加元素

    default Builder<T> add(T t) {
    accept(t);
    return this;
    }

    Stream<T> build(); // ✅ 工厂方法:build 出 Stream
    }

    /**
    * ✅ 工厂方法:获取 Builder
    */

    static <T> Builder<T> builder() {
    return new Streams.StreamBuilderImpl<>();
    }
    }

    完整使用:

    /**
    * ✅ 链式构建 Stream
    */

    Stream<String> stream = Stream.<String>builder()
    .add("Hello")
    .add("World")
    .add("!")
    .build();

    stream.forEach(System.out::println);

    关键点:

    方法作用
    add(T t) 链式添加元素(返回 this)
    accept(T t) Consumer 接口实现(返回 this)
    build() 不可再变的 Stream

    为什么 Stream 用 Builder?

  • Stream 不可变:构造完不能再加元素
  • 支持多个元素:可以一次添加多个 add()
  • 类型安全:<T> 泛型保证类型
  • 2.3 ByteBuffer —— NIO 的"字节缓冲区建造者"

    源码位置:

    • OpenJDK 17
    • src/java.base/share/classes/java/nio/ByteBuffer.java

    核心源码(简化版):

    public abstract class ByteBuffer extends Buffer
    implements Comparable<ByteBuffer> {

    // … 字段 …

    /**
    * ✅ 链式 put:每一步都返回 this
    */

    public ByteBuffer put(byte b) {
    // 实际逻辑在 HeapByteBuffer 中
    return this;
    }

    public ByteBuffer put(int index, byte b) {
    // …
    return this;
    }

    /**
    * ✅ 链式 put(多字节)
    */

    public ByteBuffer put(byte[] src, int offset, int length) {
    // …
    return this;
    }

    /**
    * ✅ 链式 flip:切换读写模式
    */

    public ByteBuffer flip() {
    super.flip();
    return this;
    }
    }

    完整使用:

    /**
    * ✅ 链式构造 ByteBuffer
    */

    ByteBuffer buffer = ByteBuffer.allocate(1024)
    .put((byte) 1)
    .put((byte) 2)
    .put((byte) 3)
    .flip(); // 切到读模式

    while (buffer.hasRemaining()) {
    System.out.println(buffer.get());
    }

    关键点:

    方法作用
    allocate(int) 工厂方法分配内存
    put(…) 链式写入数据
    flip() 切换读写模式
    get() 读数据

    为什么 ByteBuffer 是"建造者"?

  • 分阶段使用:写 → flip → 读
  • 状态机:position / limit / capacity 三个状态
  • 链式调用:所有"装"操作都返回 this
  • 2.4 JDK 建造者的"作者选择"

    JDK 类链式方法数选 Builder 原因
    StringBuilder 10+ 高频操作,极致简洁
    Stream.Builder 3 流式 API,不可变结果
    ByteBuffer 20+ 分阶段状态管理
    Locale.Builder 10 复杂配置对象

    规律:

    JDK 的建造者倾向于"链式 + 极简"——没有 Director,没有显式 build(),方法名直接就是操作名。这是 JDK 的"轻量级建造者"风格。


    三、Spring / MyBatis 源码剖析:URL 与 SQL 建造者

    3.1 Spring UriComponentsBuilder —— URL 拼装的"标准建造者"

    源码位置:

    • Spring Framework 6.1.x
    • spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java

    核心源码(简化版):

    public class UriComponentsBuilder implements UriBuilder, Cloneable {

    private String scheme;
    private String ssp;
    private String userInfo;
    private String host;
    private String port;
    private CompositePathComponentBuilder pathBuilder;
    private MultiValueMap<String, String> queryParams;
    private String fragment;

    /**
    * ✅ 工厂方法:创建 Builder
    */

    public static UriComponentsBuilder newInstance() {
    return new UriComponentsBuilder();
    }

    public static UriComponentsBuilder fromPath(String path) {
    return new UriComponentsBuilder().path(path);
    }

    public static UriComponentsBuilder fromUri(String uri) {
    return new UriComponentsBuilder().uri(uri);
    }

    /**
    * ✅ 链式设置 scheme
    */

    public UriComponentsBuilder scheme(String scheme) {
    this.scheme = scheme;
    return this;
    }

    /**
    * ✅ 链式设置 host
    */

    public UriComponentsBuilder host(String host) {
    this.host = host;
    return this;
    }

    /**
    * ✅ 链式设置 port
    */

    public UriComponentsBuilder port(int port) {
    this.port = String.valueOf(port);
    return this;
    }

    /**
    * ✅ 链式设置 path
    */

    public UriComponentsBuilder path(String path) {
    this.pathBuilder.addPath(path);
    return this;
    }

    /**
    * ✅ 链式添加 query 参数
    */

    public UriComponentsBuilder queryParam(String name, Object... values) {
    this.queryParams.add(name, Arrays.stream(values).map(Object::toString).toArray(String[]::new));
    return this;
    }

    /**
    * ✅ 链式设置 fragment
    */

    public UriComponentsBuilder fragment(String fragment) {
    this.fragment = fragment;
    return this;
    }

    /**
    * ✅ 工厂方法:build 出 UriComponents
    */

    public UriComponents build() {
    return buildInternal(false);
    }

    public UriComponents build(boolean encoded) {
    return buildInternal(encoded);
    }

    /**
    * ✅ 模板方法:build 内部逻辑
    */

    private UriComponents buildInternal(boolean encoded) {
    // 1. 组合 path
    // 2. 处理 query
    // 3. 处理 fragment
    // 4. 返回 UriComponents
    return new UriComponents(scheme, ssp, userInfo, host, port,
    pathBuilder.build(), queryParams, fragment, encoded);
    }
    }

    完整使用:

    /**
    * ✅ 链式拼装 URL
    */

    URI uri = UriComponentsBuilder.newInstance()
    .scheme("https")
    .host("api.dabai.com")
    .path("/orders/{id}")
    .queryParam("source", "PC")
    .queryParam("userId", "{userId}")
    .build()
    .expand("ORDER_001", 1001L)
    .toUri();

    // 最终 URL:https://api.dabai.com/orders/ORDER_001?source=PC&userId=1001

    关键点:

    方法作用
    newInstance() / fromPath() 工厂方法获取 Builder
    scheme() / host() / port() 链式设置各个部分
    path() 链式添加路径(支持占位符)
    queryParam() 链式添加 query 参数
    build() build 出 UriComponents
    expand() 替换占位符

    为什么 UriComponentsBuilder 是"建造者"?

  • URL 字段多:scheme/host/port/path/query/fragment 一共 6 个
  • 分步构造:每个部分独立设置
  • 占位符支持:{id} / {userId} 可以后期 expand
  • 不可变结果:build() 后 UriComponents 不可变
  • 3.2 Spring HttpHeaders —— HTTP 头的"链式封装"

    源码位置:

    • Spring Framework 6.1.x
    • spring-web/src/main/java/org/springframework/http/HttpHeaders.java

    核心源码(简化版):

    public class HttpHeaders implements MultiValueMap<String, String> {

    private final Map<String, List<String>> headers;

    /**
    * ✅ 工厂方法:创建空的 HttpHeaders
    */

    public static HttpHeaders empty() {
    return new HttpHeaders(CollectionUtils.toMultiValueMap(new LinkedCaseInsensitiveMap<>()));
    }

    public static HttpHeaders writableHttpHeaders(HttpHeaders headers) {
    return new WritableHttpHeaders(headers);
    }

    /**
    * ✅ 链式添加单值头
    */

    public HttpHeaders add(String headerName, String headerValue) {
    this.headers.putIfAbsent(headerName, new ArrayList<>());
    this.headers.get(headerName).add(headerValue);
    return this;
    }

    /**
    * ✅ 链式设置 Content-Type
    */

    public HttpHeaders contentType(MediaType mediaType) {
    return set(CONTENT_TYPE, mediaType.toString());
    }

    /**
    * ✅ 链式设置 Authorization
    */

    public HttpHeaders setBearerAuth(String token) {
    return set(AUTHORIZATION, "Bearer " + token);
    }

    // … 大量链式 setter
    }

    完整使用:

    /**
    * ✅ 链式构造 HTTP 头
    */

    HttpHeaders headers = HttpHeaders.empty()
    .contentType(MediaType.APPLICATION_JSON)
    .setBearerAuth("xxx-xxx-xxx")
    .add("X-Request-Id", "REQ_001")
    .add("X-User-Id", "1001");

    关键点:

    特点解释
    链式调用 所有 setter 返回 this
    类型安全 提供常用 header 的强类型方法(setBearerAuth)
    大小写不敏感 用 LinkedCaseInsensitiveMap

    3.3 MyBatis SqlSessionFactoryBuilder —— 复杂 SQL 会话工厂的"重型建造者"

    源码位置:

    • MyBatis 3.5.x
    • src/main/java/org/apache/ibatis/session/SqlSessionFactoryBuilder.java

    核心源码:

    public class SqlSessionFactoryBuilder {

    /**
    * ✅ 工厂方法入口
    */

    public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
    }

    public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
    // 1️⃣ 解析 XML(用 XMLConfigBuilder 解析)
    XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
    // 2️⃣ 解析得到 Configuration
    Configuration config = parser.parse();
    // 3️⃣ 工厂方法:build 出 SqlSessionFactory
    return build(config);
    } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
    ErrorContext.instance().reset();
    }
    }

    /**
    * ✅ 工厂方法:build 出 SqlSessionFactory
    */

    public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
    }
    }

    注意:MyBatis 的 SqlSessionFactoryBuilder 不是典型的"链式建造者",而是"工厂方法"风格的建造者——只有 1 个核心 build() 方法,不返回 this。

    MyBatis 用法:

    /**
    * 经典用法
    */

    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);

    // ✅ 链式构造 SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    为什么 MyBatis 的 Builder 是"极简"风格?

  • 输入是 XML:所有配置都在 XML 里
  • build 只调一次:构造 SqlSessionFactory 是启动期操作,不是高频
  • 重点在 build 内部:XML 解析 + Configuration 构建逻辑复杂
  • SqlSessionFactoryBuilder 的产品族:

    SqlSessionFactoryBuilder
    ↓ build(Reader)
    XMLConfigBuilder
    ↓ parse()
    Configuration
    ↓ build()
    DefaultSqlSessionFactory

    为什么这里不是"经典 4 角色"建造者?

    因为 MyBatis 的"复杂对象"是 SqlSessionFactory,所有配置在 XML 里。Builder 只是"读取 XML + 创建对象"的桥梁。不是分步构造,而是"一次解析 + 一次创建"。

    3.4 中间件建造者对比表

    框架建造者类复杂对象链式 / 分步
    JDK StringBuilder String 链式
    JDK Stream.Builder Stream 链式
    JDK ByteBuffer 字节缓冲区 链式
    Spring UriComponentsBuilder UriComponents 链式
    Spring HttpHeaders HTTP 头 链式
    MyBatis SqlSessionFactoryBuilder SqlSessionFactory 工厂方法(不链式)

    规律:

    JDK / Spring 倾向"链式",MyBatis 倾向"工厂方法"。原因:JDK/Spring 的建造者是运行时高频操作(URL 拼装、字符串拼接),需要链式简洁;MyBatis 是启动期低频操作,工厂方法足够。


    四、为什么框架作者这么设计?

    读源码看的是"实现",悟的是"设计哲学"。

    4.1 框架作者选建造者的 4 个核心考虑

    序号考虑举例
    对象字段多 URL 6 个、订单 30+
    构造过程分步 字符串拼接、URL 拼装
    需要不可变结果 String、Stream、UriComponents
    高频操作需要简洁 字符串拼接

    4.2 链式 vs 分步:源码里怎么选?

    场景选哪个原因
    运行时高频(字符串、URL) 链式 极简,无中间变量
    构造期低频(启动期) 分步 可读性 > 简洁性
    需要 Director 分步 固定流程,可封装
    没有固定流程 链式 灵活拼接

    4.3 框架作者不选建造者的 3 种情况

    序号场景源码举例
    对象字段少于 3 个 简单 DTO(用构造方法)
    构造过程不可分 解析 XML(用工厂方法)
    需要可变对象 JavaBean(用 setter)

    4.4 建造者 vs 工厂方法:源码里怎么选?

    场景选哪个原因
    复杂对象分步构造 建造者 URL、字符串、订单
    按类型创建对象 工厂方法 支付渠道、日志框架
    配套 API 抽象工厂 JDBC Connection、Document

    五、借鉴到我们项目:3 个"抄作业"实践

    5.1 实践 1:SQL 查询建造者

    场景:动态 SQL 拼装(条件查询)。

    完整实现:

    /**
    * 借鉴 UriComponentsBuilder:动态 SQL 查询
    */

    public class SqlQueryBuilder {

    private StringBuilder select = new StringBuilder("SELECT *");
    private StringBuilder from = new StringBuilder();
    private StringBuilder where = new StringBuilder();
    private StringBuilder orderBy = new StringBuilder();
    private StringBuilder limit = new StringBuilder();
    private List<Object> params = new ArrayList<>();

    /**
    * ✅ 链式:设置 SELECT
    */

    public SqlQueryBuilder select(String... columns) {
    this.select = new StringBuilder("SELECT " + String.join(", ", columns));
    return this;
    }

    /**
    * ✅ 链式:设置 FROM
    */

    public SqlQueryBuilder from(String table) {
    this.from = new StringBuilder(" FROM " + table);
    return this;
    }

    /**
    * ✅ 链式:添加 WHERE 条件
    */

    public SqlQueryBuilder where(String condition, Object... values) {
    if (this.where.length() == 0) {
    this.where.append(" WHERE ");
    } else {
    this.where.append(" AND ");
    }
    this.where.append(condition);
    this.params.addAll(Arrays.asList(values));
    return this;
    }

    /**
    * ✅ 链式:设置 ORDER BY
    */

    public SqlQueryBuilder orderBy(String column, boolean desc) {
    this.orderBy.append(" ORDER BY ").append(column);
    if (desc) this.orderBy.append(" DESC");
    return this;
    }

    /**
    * ✅ 链式:设置 LIMIT
    */

    public SqlQueryBuilder limit(int limit, int offset) {
    this.limit.append(" LIMIT ").append(limit).append(" OFFSET ").append(offset);
    return this;
    }

    /**
    * ✅ 工厂方法:build 出 SQL
    */

    public QueryResult build() {
    String sql = select.toString()
    + from.toString()
    + where.toString()
    + orderBy.toString()
    + limit.toString();
    return new QueryResult(sql, params);
    }

    /**
    * 查询结果:SQL + 参数
    */

    public record QueryResult(String sql, List<Object> params) {}
    }

    使用示例:

    /**
    * ✅ 链式构造 SQL
    */

    QueryResult query = new SqlQueryBuilder()
    .select("id", "name", "price")
    .from("orders")
    .where("user_id = ?", 1001L)
    .where("status = ?", "PAID")
    .orderBy("create_time", true)
    .limit(20, 0)
    .build();

    // sql = "SELECT id, name, price FROM orders WHERE user_id = ? AND status = ? ORDER BY create_time DESC LIMIT 20 OFFSET 0"
    // params = [1001L, "PAID"]

    收益:

    优化点效果
    链式调用 条件动态拼装,可读性高
    统一参数收集 不再到处拼接 ?
    类型安全 编译期检查参数类型

    5.2 实践 2:HTTP 客户端请求建造者

    场景:调用第三方 API 时的请求拼装。

    完整实现:

    /**
    * 借鉴 UriComponentsBuilder:HTTP 请求建造者
    */

    public class HttpRequestBuilder {

    private String method = "GET";
    private String url;
    private HttpHeaders headers = new HttpHeaders();
    private String body;
    private Duration timeout = Duration.ofSeconds(10);

    /**
    * ✅ 链式:设置方法
    */

    public HttpRequestBuilder method(String method) {
    this.method = method;
    return this;
    }

    public HttpRequestBuilder get() {
    return method("GET");
    }

    public HttpRequestBuilder post() {
    return method("POST");
    }

    public HttpRequestBuilder put() {
    return method("PUT");
    }

    public HttpRequestBuilder delete() {
    return method("DELETE");
    }

    /**
    * ✅ 链式:设置 URL
    */

    public HttpRequestBuilder url(String url) {
    this.url = url;
    return this;
    }

    /**
    * ✅ 链式:设置 URL(带占位符)
    */

    public HttpRequestBuilder url(String urlTemplate, Object... uriVars) {
    URI uri = UriComponentsBuilder.fromUriString(urlTemplate)
    .buildAndExpand(uriVars)
    .encode()
    .toUri();
    this.url = uri.toString();
    return this;
    }

    /**
    * ✅ 链式:添加 Header
    */

    public HttpRequestBuilder header(String name, String value) {
    this.headers.add(name, value);
    return this;
    }

    /**
    * ✅ 链式:设置 JSON Body
    */

    public HttpRequestBuilder jsonBody(Object body) {
    this.headers.setContentType(MediaType.APPLICATION_JSON);
    try {
    this.body = new ObjectMapper().writeValueAsString(body);
    } catch (JsonProcessingException e) {
    throw new RuntimeException("序列化请求体失败", e);
    }
    return this;
    }

    /**
    * ✅ 链式:设置超时
    */

    public HttpRequestBuilder timeout(Duration timeout) {
    this.timeout = timeout;
    return this;
    }

    /**
    * ✅ 工厂方法:build 出 HTTP 请求
    */

    public HttpRequest build() {
    if (url == null) {
    throw new IllegalArgumentException("URL 不能为空");
    }
    return new HttpRequest(method, url, headers, body, timeout);
    }

    /**
    * HTTP 请求对象(不可变)
    */

    public record HttpRequest(
    String method,
    String url,
    HttpHeaders headers,
    String body,
    Duration timeout
    ) {}
    }

    使用示例:

    /**
    * ✅ 链式构造 HTTP 请求
    */

    HttpRequest request = new HttpRequestBuilder()
    .post()
    .url("https://api.dabai.com/orders/{id}", "ORDER_001")
    .header("Authorization", "Bearer xxx")
    .header("X-Request-Id", "REQ_001")
    .jsonBody(orderRequest)
    .timeout(Duration.ofSeconds(5))
    .build();

    收益:

    优化点效果
    链式调用 请求拼装清晰
    URL 占位符 自动 expand
    不可变结果 线程安全
    统一超时 避免每个调用都设置

    5.3 实践 3:分页参数建造者

    场景:所有分页查询统一分页参数。

    完整实现:

    /**
    * 借鉴 UriComponentsBuilder:分页参数建造者
    */

    public class PageQueryBuilder {

    private int pageNum = 1;
    private int pageSize = 20;
    private String orderBy;
    private boolean asc = true;
    private final Map<String, Object> filters = new HashMap<>();

    /**
    * ✅ 链式:设置页码
    */

    public PageQueryBuilder pageNum(int pageNum) {
    if (pageNum < 1) {
    throw new IllegalArgumentException("页码不能小于 1");
    }
    this.pageNum = pageNum;
    return this;
    }

    /**
    * ✅ 链式:设置每页大小
    */

    public PageQueryBuilder pageSize(int pageSize) {
    if (pageSize < 1 || pageSize > 1000) {
    throw new IllegalArgumentException("每页大小必须在 1~1000 之间");
    }
    this.pageSize = pageSize;
    return this;
    }

    /**
    * ✅ 链式:设置排序
    */

    public PageQueryBuilder orderBy(String orderBy) {
    this.orderBy = orderBy;
    return this;
    }

    public PageQueryBuilder asc() {
    this.asc = true;
    return this;
    }

    public PageQueryBuilder desc() {
    this.asc = false;
    return this;
    }

    /**
    * ✅ 链式:添加过滤条件
    */

    public PageQueryBuilder filter(String key, Object value) {
    if (value != null) {
    this.filters.put(key, value);
    }
    return this;
    }

    /**
    * ✅ 工厂方法:build 出分页参数
    */

    public PageQuery build() {
    int offset = (pageNum 1) * pageSize;
    return new PageQuery(pageNum, pageSize, offset, orderBy, asc, filters);
    }

    /**
    * 分页参数(不可变)
    */

    public record PageQuery(
    int pageNum,
    int pageSize,
    int offset,
    String orderBy,
    boolean asc,
    Map<String, Object> filters
    ) {}
    }

    使用示例:

    /**
    * ✅ 链式构造分页参数
    */

    PageQuery query = new PageQueryBuilder()
    .pageNum(1)
    .pageSize(20)
    .orderBy("create_time")
    .desc()
    .filter("status", "PAID")
    .filter("user_id", 1001L)
    .build();

    收益:

    优化点效果
    链式调用 分页参数清晰
    自动 offset 计算 不再算 offset = (page-1) * size
    默认值合理 pageNum=1, pageSize=20
    校验集中 在 builder 里校验

    六、本篇小结 + 下一模式预告

    6.1 本篇小结(5 个核心要点)

  • JDK 链式建造者:StringBuilder / Stream.Builder / ByteBuffer,运行时高频操作首选。
  • Spring 链式建造者:UriComponentsBuilder / HttpHeaders,URL/HTTP 拼装标准做法。
  • MyBatis 工厂式建造者:SqlSessionFactoryBuilder,启动期低频操作用工厂方法足够。
  • 选型规律:运行时高频用链式,启动期低频用工厂方法。
  • 借鉴价值:SQL 查询、HTTP 请求、分页参数,链式 Builder 提升可读性 + 不可变 + 校验。
  • 6.2 一句话总结

    建造者在源码里不是"教科书式"的 Director + Builder,而是"链式调用 + 自动校验"的简化版。JDK 用链式做高频操作,Spring 用链式拼 URL/Header,MyBatis 用工厂方法做启动期配置。选 Builder 还是 Factory,看操作频率。

    6.3 知识脑图

    建造者源码剖析
    ├── JDK
    │ ├── StringBuilder(链式 append)
    │ ├── Stream.Builder(链式 add + build)
    │ └── ByteBuffer(链式 put + flip)
    ├── Spring
    │ ├── UriComponentsBuilder(URL 拼装)
    │ └── HttpHeaders(HTTP 头链式封装)
    ├── MyBatis
    │ └── SqlSessionFactoryBuilder(工厂方法式)
    └── 借鉴价值
    ├── SQL 查询建造者(动态 SQL)
    ├── HTTP 请求建造者(请求拼装)
    └── 分页参数建造者(分页统一)

    6.4 下一模式预告

    第 10 篇【原型模式 – 业务实战篇】:大白商城商品 SKU 克隆的"复制魔法"

    下一篇我们会实战原型模式,回答 4 个问题:

  • 什么时候需要"复制"一个对象?
  • 浅克隆 vs 深克隆的核心区别是什么?
  • Java Cloneable 接口的优缺点是什么?
  • 拷贝构造 / 序列化 / MapStruct 替代方案怎么选?
  • 并附完整的商品克隆代码(含浅克隆 / 深克隆 / MapStruct 三种实现 + 单元测试),可直接复制到 IDEA 跑。


    觉得对您有帮助,麻烦点点关注啦,您的关注是我创作的最大动力~ 🎯

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 大白话说Java设计模式-09-建造者模式(源码剖析篇)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!