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

📌 PDF:AI人工智能 — RAG知识库实战项目

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

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

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


目录


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

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

源码地图

类别框架 / 中间件建造者类复杂对象
JDKjava.langStringBuilderString
JDKjava.langStringBufferString(线程安全)
JDKjava.util.streamStream.BuilderStream
JDKjava.nioByteBuffer字节缓冲区
JDKjava.utilLocale.BuilderLocale
SpringSpring WebUriComponentsBuilderURI
SpringSpring WebHttpHeadersHTTP 头
MyBatisMyBatisSqlSessionFactoryBuilderSqlSessionFactory
LombokLombok@Builder 注解任意类
GuavaGuavaImmutableList.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 是"建造者"?

  1. 分步构造append() 一次又一次地"装部件"
  2. 链式调用:每个 append 都返回 this
  3. 不可变结果toString() 产出不可变的 String
  4. 半成品支持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?

  1. Stream 不可变:构造完不能再加元素
  2. 支持多个元素:可以一次添加多个 add()
  3. 类型安全<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 是"建造者"?

  1. 分阶段使用:写 → flip → 读
  2. 状态机:position / limit / capacity 三个状态
  3. 链式调用:所有"装"操作都返回 this

2.4 JDK 建造者的"作者选择"

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

规律

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 是"建造者"?

  1. URL 字段多:scheme/host/port/path/query/fragment 一共 6 个
  2. 分步构造:每个部分独立设置
  3. 占位符支持{id} / {userId} 可以后期 expand
  4. 不可变结果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 是"极简"风格?

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

SqlSessionFactoryBuilder 的产品族

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

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

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

3.4 中间件建造者对比表

框架建造者类复杂对象链式 / 分步
JDKStringBuilderString链式
JDKStream.BuilderStream链式
JDKByteBuffer字节缓冲区链式
SpringUriComponentsBuilderUriComponents链式
SpringHttpHeadersHTTP 头链式
MyBatisSqlSessionFactoryBuilderSqlSessionFactory工厂方法(不链式)

规律

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


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

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

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

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

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 个核心要点)

  1. JDK 链式建造者StringBuilder / Stream.Builder / ByteBuffer运行时高频操作首选。
  2. Spring 链式建造者UriComponentsBuilder / HttpHeadersURL/HTTP 拼装标准做法。
  3. MyBatis 工厂式建造者SqlSessionFactoryBuilder启动期低频操作用工厂方法足够。
  4. 选型规律运行时高频用链式,启动期低频用工厂方法
  5. 借鉴价值: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 个问题:

  1. 什么时候需要"复制"一个对象?
  2. 浅克隆 vs 深克隆的核心区别是什么?
  3. Java Cloneable 接口的优缺点是什么?
  4. 拷贝构造 / 序列化 / MapStruct 替代方案怎么选?

并附完整的商品克隆代码(含浅克隆 / 深克隆 / MapStruct 三种实现 + 单元测试),可直接复制到 IDEA 跑


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

计算机小能手(AI+Java)

若对您有所帮助,请点点关注哟~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值