StepBuilder模式详解

Step Builder模式实战指南:构建类型安全的流式API

一、什么是Step Builder模式

1.1 传统Builder模式的局限性

在Java开发中,我们经常使用Builder模式来构建复杂对象。传统的Builder模式虽然解决了构造函数参数过多的问题,但存在一个明显的缺陷:无法在编译期保证必填参数的完整性

传统Builder的问题示例:

java 复制代码
// 传统Builder模式
public class User {
    private String username;    // 必填
    private String password;    // 必填
    private String email;       // 必填
    private String phone;       // 可选
    private Integer age;        // 可选

    public static class Builder {
        private String username;
        private String password;
        private String email;
        private String phone;
        private Integer age;

        public Builder username(String username) {
            this.username = username;
            return this;
        }

        public Builder password(String password) {
            this.password = password;
            return this;
        }

        public Builder email(String email) {
            this.email = email;
            return this;
        }

        public Builder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public Builder age(Integer age) {
            this.age = age;
            return this;
        }

        public User build() {
            // 运行时检查,容易遗漏
            if (username == null || password == null || email == null) {
                throw new IllegalStateException("缺少必填字段");
            }
            return new User(this);
        }
    }
}

// 使用时可能会忘记设置必填字段
User user = new User.Builder()
    .username("john")
    // 忘记设置password和email
    .phone("123456")
    .build();  // 运行时才会抛出异常!

1.2 Step Builder模式的优势

Step Builder模式(也称为Staged Builder或Telescopic Builder)通过类型系统在编译期强制要求按顺序设置必填参数,从而避免了运行时错误。

核心思想:

  • 每个必填参数对应一个构建步骤(Step)
  • 每个步骤只暴露下一步需要的方法
  • 利用接口和泛型确保类型安全
  • 编译器强制完成所有必填步骤

Step Builder的调用流程:

复制代码
Step 1: Username    Step 2: Password    Step 3: Email    Step 4: Build
   ↓                    ↓                   ↓                ↓
[username()] ──→ [password()] ──→ [email()] ──→ [build()]
                                               [phone()]
                                               [age()]

二、Step Builder基础实现

2.1 简单示例:用户注册

java 复制代码
package com.example.builder;

/**
 * Step Builder模式 - 用户注册示例
 */
public class User {

    private final String username;
    private final String password;
    private final String email;
    private final String phone;
    private final Integer age;

    private User(Builder builder) {
        this.username = builder.username;
        this.password = builder.password;
        this.email = builder.email;
        this.phone = builder.phone;
        this.age = builder.age;
    }

    // ============ Step Builder接口定义 ============

    /**
     * 步骤1: 设置用户名
     */
    public interface UsernameStep {
        PasswordStep username(String username);
    }

    /**
     * 步骤2: 设置密码
     */
    public interface PasswordStep {
        EmailStep password(String password);
    }

    /**
     * 步骤3: 设置邮箱
     */
    public interface EmailStep {
        BuildStep email(String email);
    }

    /**
     * 步骤4: 构建对象(可选参数)
     */
    public interface BuildStep {
        BuildStep phone(String phone);
        BuildStep age(Integer age);
        User build();
    }

    // ============ Builder实现类 ============

    private static class Builder implements UsernameStep, PasswordStep, EmailStep, BuildStep {

        private String username;
        private String password;
        private String email;
        private String phone;
        private Integer age;

        @Override
        public PasswordStep username(String username) {
            this.username = username;
            return this;
        }

        @Override
        public EmailStep password(String password) {
            this.password = password;
            return this;
        }

        @Override
        public BuildStep email(String email) {
            this.email = email;
            return this;
        }

        @Override
        public BuildStep phone(String phone) {
            this.phone = phone;
            return this;
        }

        @Override
        public BuildStep age(Integer age) {
            this.age = age;
            return this;
        }

        @Override
        public User build() {
            return new User(this);
        }
    }

    // ============ 静态工厂方法 ============

    public static UsernameStep builder() {
        return new Builder();
    }

    // Getters
    public String getUsername() { return username; }
    public String getPassword() { return password; }
    public String getEmail() { return email; }
    public String getPhone() { return phone; }
    public Integer getAge() { return age; }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", phone='" + phone + '\'' +
                ", age=" + age +
                '}';
    }
}

使用示例:

java 复制代码
public class StepBuilderDemo {

    public static void main(String[] args) {
        // ✅ 正确使用 - 编译通过
        User user1 = User.builder()
                .username("john_doe")
                .password("securePass123")
                .email("john@example.com")
                .phone("1234567890")
                .age(25)
                .build();

        System.out.println(user1);

        // ✅ 只设置必填字段
        User user2 = User.builder()
                .username("jane_doe")
                .password("password456")
                .email("jane@example.com")
                .build();

        System.out.println(user2);

        // ❌ 编译错误 - 缺少必填字段
        // User user3 = User.builder()
        //         .username("alice")
        //         .build();  // 编译失败:找不到build()方法
    }
}

2.2 工作原理分析

复制代码
类型系统保证调用顺序:

User.builder()                     返回类型: UsernameStep
    ↓ 只能调用username()
.username("john")                  返回类型: PasswordStep
    ↓ 只能调用password()
.password("pass123")               返回类型: EmailStep
    ↓ 只能调用email()
.email("john@example.com")         返回类型: BuildStep
    ↓ 可以调用phone()、age()或build()
.phone("123456")                   返回类型: BuildStep
    ↓ 可以调用age()或build()
.build()                           返回类型: User

类型安全的关键:

  1. 接口链:每个步骤返回不同的接口类型
  2. 单一实现:Builder类实现所有接口
  3. 方法可见性:每个接口只暴露特定方法
  4. 编译期检查:IDE和编译器强制按顺序调用

三、实战案例:HTTP请求构建器

3.1 场景分析

在构建HTTP客户端时,某些参数是必需的(如URL、HTTP方法),而某些是可选的(如请求头、超时时间)。使用Step Builder可以确保必填参数不会遗漏。

3.2 完整实现

java 复制代码
package com.example.http;

import java.util.*;

/**
 * HTTP请求构建器 - Step Builder模式
 */
public class HttpRequest {

    private final String url;
    private final HttpMethod method;
    private final Map<String, String> headers;
    private final String body;
    private final int timeoutSeconds;
    private final boolean followRedirects;

    public enum HttpMethod {
        GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
    }

    private HttpRequest(Builder builder) {
        this.url = builder.url;
        this.method = builder.method;
        this.headers = Collections.unmodifiableMap(new HashMap<>(builder.headers));
        this.body = builder.body;
        this.timeoutSeconds = builder.timeoutSeconds;
        this.followRedirects = builder.followRedirects;
    }

    // ============ Step接口定义 ============

    public interface UrlStep {
        MethodStep url(String url);
    }

    public interface MethodStep {
        BuildStep method(HttpMethod method);
        BuildStep get();
        BuildStep post();
        BuildStep put();
        BuildStep delete();
    }

    public interface BuildStep {
        BuildStep header(String key, String value);
        BuildStep headers(Map<String, String> headers);
        BuildStep body(String body);
        BuildStep timeout(int seconds);
        BuildStep followRedirects(boolean follow);
        HttpRequest build();
    }

    // ============ Builder实现 ============

    private static class Builder implements UrlStep, MethodStep, BuildStep {

        private String url;
        private HttpMethod method;
        private Map<String, String> headers = new HashMap<>();
        private String body;
        private int timeoutSeconds = 30;  // 默认30秒
        private boolean followRedirects = true;

        @Override
        public MethodStep url(String url) {
            if (url == null || url.trim().isEmpty()) {
                throw new IllegalArgumentException("URL不能为空");
            }
            this.url = url;
            return this;
        }

        @Override
        public BuildStep method(HttpMethod method) {
            this.method = method;
            return this;
        }

        @Override
        public BuildStep get() {
            return method(HttpMethod.GET);
        }

        @Override
        public BuildStep post() {
            return method(HttpMethod.POST);
        }

        @Override
        public BuildStep put() {
            return method(HttpMethod.PUT);
        }

        @Override
        public BuildStep delete() {
            return method(HttpMethod.DELETE);
        }

        @Override
        public BuildStep header(String key, String value) {
            this.headers.put(key, value);
            return this;
        }

        @Override
        public BuildStep headers(Map<String, String> headers) {
            this.headers.putAll(headers);
            return this;
        }

        @Override
        public BuildStep body(String body) {
            this.body = body;
            return this;
        }

        @Override
        public BuildStep timeout(int seconds) {
            if (seconds <= 0) {
                throw new IllegalArgumentException("超时时间必须大于0");
            }
            this.timeoutSeconds = seconds;
            return this;
        }

        @Override
        public BuildStep followRedirects(boolean follow) {
            this.followRedirects = follow;
            return this;
        }

        @Override
        public HttpRequest build() {
            return new HttpRequest(this);
        }
    }

    // ============ 静态工厂方法 ============

    public static UrlStep builder() {
        return new Builder();
    }

    // ============ 执行方法 ============

    public void execute() {
        System.out.println("执行HTTP请求:");
        System.out.println("  URL: " + url);
        System.out.println("  Method: " + method);
        System.out.println("  Headers: " + headers);
        System.out.println("  Body: " + body);
        System.out.println("  Timeout: " + timeoutSeconds + "s");
        System.out.println("  Follow Redirects: " + followRedirects);
    }

    // Getters
    public String getUrl() { return url; }
    public HttpMethod getMethod() { return method; }
    public Map<String, String> getHeaders() { return headers; }
    public String getBody() { return body; }
    public int getTimeoutSeconds() { return timeoutSeconds; }
    public boolean isFollowRedirects() { return followRedirects; }
}

使用示例:

java 复制代码
public class HttpRequestDemo {

    public static void main(String[] args) {
        // GET请求
        HttpRequest getRequest = HttpRequest.builder()
                .url("https://api.example.com/users")
                .get()
                .header("Authorization", "Bearer token123")
                .header("Accept", "application/json")
                .timeout(60)
                .build();

        getRequest.execute();

        System.out.println("\n" + "=".repeat(50) + "\n");

        // POST请求
        HttpRequest postRequest = HttpRequest.builder()
                .url("https://api.example.com/users")
                .post()
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer token456")
                .body("{\"name\":\"John\",\"email\":\"john@example.com\"}")
                .timeout(30)
                .followRedirects(false)
                .build();

        postRequest.execute();

        System.out.println("\n" + "=".repeat(50) + "\n");

        // PUT请求 - 使用便捷方法
        HttpRequest putRequest = HttpRequest.builder()
                .url("https://api.example.com/users/123")
                .put()
                .headers(Map.of(
                    "Content-Type", "application/json",
                    "Authorization", "Bearer token789"
                ))
                .body("{\"name\":\"Jane\"}")
                .build();

        putRequest.execute();
    }
}

四、开源框架中的Step Builder应用

4.1 OkHttp Request Builder分析

虽然OkHttp的Request.Builder不是严格的Step Builder,但我们可以用Step Builder改进它:

java 复制代码
package com.example.okhttp;

import okhttp3.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 改进的OkHttp请求构建器
 */
public class StepOkHttpRequest {

    private final Request request;
    private final OkHttpClient client;

    private StepOkHttpRequest(Builder builder) {
        Request.Builder requestBuilder = new Request.Builder()
                .url(builder.url);

        // 设置HTTP方法和请求体
        switch (builder.method) {
            case GET:
                requestBuilder.get();
                break;
            case POST:
                requestBuilder.post(builder.requestBody);
                break;
            case PUT:
                requestBuilder.put(builder.requestBody);
                break;
            case DELETE:
                if (builder.requestBody != null) {
                    requestBuilder.delete(builder.requestBody);
                } else {
                    requestBuilder.delete();
                }
                break;
        }

        // 添加请求头
        builder.headers.forEach(requestBuilder::addHeader);

        this.request = requestBuilder.build();
        this.client = builder.client != null ? builder.client : new OkHttpClient();
    }

    public enum Method {
        GET, POST, PUT, DELETE
    }

    // ============ Step接口定义 ============

    public interface UrlStep {
        MethodStep url(String url);
    }

    public interface MethodStep {
        BuildStep get();
        BodyStep post();
        BodyStep put();
        BuildStep delete();
    }

    public interface BodyStep {
        BuildStep jsonBody(String json);
        BuildStep formBody(Map<String, String> formData);
        BuildStep emptyBody();
    }

    public interface BuildStep {
        BuildStep header(String name, String value);
        BuildStep client(OkHttpClient client);
        StepOkHttpRequest build();
    }

    // ============ Builder实现 ============

    private static class Builder implements UrlStep, MethodStep, BodyStep, BuildStep {

        private String url;
        private Method method;
        private RequestBody requestBody;
        private Map<String, String> headers = new HashMap<>();
        private OkHttpClient client;

        @Override
        public MethodStep url(String url) {
            this.url = url;
            return this;
        }

        @Override
        public BuildStep get() {
            this.method = Method.GET;
            return this;
        }

        @Override
        public BodyStep post() {
            this.method = Method.POST;
            return this;
        }

        @Override
        public BodyStep put() {
            this.method = Method.PUT;
            return this;
        }

        @Override
        public BuildStep delete() {
            this.method = Method.DELETE;
            return this;
        }

        @Override
        public BuildStep jsonBody(String json) {
            this.requestBody = RequestBody.create(
                json,
                MediaType.parse("application/json; charset=utf-8")
            );
            return this;
        }

        @Override
        public BuildStep formBody(Map<String, String> formData) {
            FormBody.Builder formBuilder = new FormBody.Builder();
            formData.forEach(formBuilder::add);
            this.requestBody = formBuilder.build();
            return this;
        }

        @Override
        public BuildStep emptyBody() {
            this.requestBody = RequestBody.create("", null);
            return this;
        }

        @Override
        public BuildStep header(String name, String value) {
            this.headers.put(name, value);
            return this;
        }

        @Override
        public BuildStep client(OkHttpClient client) {
            this.client = client;
            return this;
        }

        @Override
        public StepOkHttpRequest build() {
            return new StepOkHttpRequest(this);
        }
    }

    // ============ 静态工厂方法 ============

    public static UrlStep builder() {
        return new Builder();
    }

    // ============ 执行方法 ============

    public Response execute() throws IOException {
        return client.newCall(request).execute();
    }

    public void enqueue(Callback callback) {
        client.newCall(request).enqueue(callback);
    }
}

使用示例:

java 复制代码
public class OkHttpStepDemo {

    public static void main(String[] args) throws IOException {
        // GET请求
        StepOkHttpRequest getRequest = StepOkHttpRequest.builder()
                .url("https://jsonplaceholder.typicode.com/posts/1")
                .get()
                .header("Accept", "application/json")
                .build();

        try (Response response = getRequest.execute()) {
            System.out.println("GET Response: " + response.body().string());
        }

        // POST请求
        StepOkHttpRequest postRequest = StepOkHttpRequest.builder()
                .url("https://jsonplaceholder.typicode.com/posts")
                .post()
                .jsonBody("{\"title\":\"foo\",\"body\":\"bar\",\"userId\":1}")
                .header("Content-Type", "application/json")
                .build();

        try (Response response = postRequest.execute()) {
            System.out.println("POST Response: " + response.body().string());
        }
    }
}

4.2 Spring RestTemplate增强

java 复制代码
package com.example.spring;

import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;

/**
 * Spring RestTemplate的Step Builder封装
 */
public class StepRestTemplate {

    private final RestTemplate restTemplate;
    private final String url;
    private final HttpMethod method;
    private final HttpHeaders headers;
    private final Object body;

    private StepRestTemplate(Builder builder) {
        this.restTemplate = builder.restTemplate != null ?
            builder.restTemplate : new RestTemplate();
        this.url = builder.url;
        this.method = builder.method;
        this.headers = builder.headers;
        this.body = builder.body;
    }

    // ============ Step接口定义 ============

    public interface UrlStep {
        MethodStep url(String url);
    }

    public interface MethodStep {
        BuildStep get();
        BodyStep post();
        BodyStep put();
        BuildStep delete();
    }

    public interface BodyStep {
        BuildStep body(Object body);
        BuildStep noBody();
    }

    public interface BuildStep {
        BuildStep header(String name, String value);
        BuildStep contentType(MediaType mediaType);
        BuildStep accept(MediaType... mediaTypes);
        BuildStep restTemplate(RestTemplate restTemplate);
        <T> T execute(Class<T> responseType);
        <T> ResponseEntity<T> executeForEntity(Class<T> responseType);
    }

    // ============ Builder实现 ============

    private static class Builder implements UrlStep, MethodStep, BodyStep, BuildStep {

        private RestTemplate restTemplate;
        private String url;
        private HttpMethod method;
        private HttpHeaders headers = new HttpHeaders();
        private Object body;

        @Override
        public MethodStep url(String url) {
            this.url = url;
            return this;
        }

        @Override
        public BuildStep get() {
            this.method = HttpMethod.GET;
            return this;
        }

        @Override
        public BodyStep post() {
            this.method = HttpMethod.POST;
            return this;
        }

        @Override
        public BodyStep put() {
            this.method = HttpMethod.PUT;
            return this;
        }

        @Override
        public BuildStep delete() {
            this.method = HttpMethod.DELETE;
            return this;
        }

        @Override
        public BuildStep body(Object body) {
            this.body = body;
            return this;
        }

        @Override
        public BuildStep noBody() {
            this.body = null;
            return this;
        }

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

        @Override
        public BuildStep contentType(MediaType mediaType) {
            this.headers.setContentType(mediaType);
            return this;
        }

        @Override
        public BuildStep accept(MediaType... mediaTypes) {
            this.headers.setAccept(Arrays.asList(mediaTypes));
            return this;
        }

        @Override
        public BuildStep restTemplate(RestTemplate restTemplate) {
            this.restTemplate = restTemplate;
            return this;
        }

        @Override
        public <T> T execute(Class<T> responseType) {
            StepRestTemplate request = new StepRestTemplate(this);
            HttpEntity<?> entity = new HttpEntity<>(request.body, request.headers);
            ResponseEntity<T> response = request.restTemplate.exchange(
                request.url,
                request.method,
                entity,
                responseType
            );
            return response.getBody();
        }

        @Override
        public <T> ResponseEntity<T> executeForEntity(Class<T> responseType) {
            StepRestTemplate request = new StepRestTemplate(this);
            HttpEntity<?> entity = new HttpEntity<>(request.body, request.headers);
            return request.restTemplate.exchange(
                request.url,
                request.method,
                entity,
                responseType
            );
        }
    }

    // ============ 静态工厂方法 ============

    public static UrlStep builder() {
        return new Builder();
    }
}

五、高级技巧与最佳实践

5.1 泛型Step Builder

使用泛型可以创建更灵活的Step Builder:

java 复制代码
package com.example.generic;

/**
 * 泛型SQL查询构建器
 */
public class SqlQuery<T> {

    private final String table;
    private final Class<T> resultType;
    private final String whereClause;
    private final String orderBy;
    private final Integer limit;

    private SqlQuery(Builder<T> builder) {
        this.table = builder.table;
        this.resultType = builder.resultType;
        this.whereClause = builder.whereClause;
        this.orderBy = builder.orderBy;
        this.limit = builder.limit;
    }

    // ============ Step接口定义 ============

    public interface TableStep<T> {
        ResultTypeStep<T> from(String table);
    }

    public interface ResultTypeStep<T> {
        BuildStep<T> resultType(Class<T> clazz);
    }

    public interface BuildStep<T> {
        BuildStep<T> where(String condition);
        BuildStep<T> orderBy(String column);
        BuildStep<T> limit(int limit);
        SqlQuery<T> build();
        List<T> execute();
    }

    // ============ Builder实现 ============

    private static class Builder<T> implements TableStep<T>, ResultTypeStep<T>, BuildStep<T> {

        private String table;
        private Class<T> resultType;
        private String whereClause;
        private String orderBy;
        private Integer limit;

        @Override
        public ResultTypeStep<T> from(String table) {
            this.table = table;
            return this;
        }

        @Override
        public BuildStep<T> resultType(Class<T> clazz) {
            this.resultType = clazz;
            return this;
        }

        @Override
        public BuildStep<T> where(String condition) {
            this.whereClause = condition;
            return this;
        }

        @Override
        public BuildStep<T> orderBy(String column) {
            this.orderBy = column;
            return this;
        }

        @Override
        public BuildStep<T> limit(int limit) {
            this.limit = limit;
            return this;
        }

        @Override
        public SqlQuery<T> build() {
            return new SqlQuery<>(this);
        }

        @Override
        public List<T> execute() {
            SqlQuery<T> query = build();
            return query.executeQuery();
        }
    }

    // ============ 静态工厂方法 ============

    public static <T> TableStep<T> select() {
        return new Builder<T>();
    }

    // ============ 执行方法 ============

    public List<T> executeQuery() {
        String sql = buildSql();
        System.out.println("执行SQL: " + sql);
        // 实际执行查询...
        return new ArrayList<>();
    }

    private String buildSql() {
        StringBuilder sql = new StringBuilder("SELECT * FROM ").append(table);
        if (whereClause != null) {
            sql.append(" WHERE ").append(whereClause);
        }
        if (orderBy != null) {
            sql.append(" ORDER BY ").append(orderBy);
        }
        if (limit != null) {
            sql.append(" LIMIT ").append(limit);
        }
        return sql.toString();
    }
}

使用示例:

java 复制代码
public class GenericBuilderDemo {

    public static class UserDto {
        private Long id;
        private String name;
        // getters and setters
    }

    public static void main(String[] args) {
        // 类型安全的查询
        List<UserDto> users = SqlQuery.<UserDto>select()
                .from("users")
                .resultType(UserDto.class)
                .where("age > 18")
                .orderBy("created_at DESC")
                .limit(10)
                .execute();

        System.out.println("查询结果: " + users);
    }
}

5.2 条件分支的Step Builder

有时需要根据条件选择不同的构建路径:

java 复制代码
package com.example.conditional;

/**
 * 支付请求构建器 - 支持多种支付方式
 */
public class PaymentRequest {

    private final String orderId;
    private final PaymentMethod method;
    private final double amount;

    // 支付宝特有字段
    private final String alipayAccount;

    // 微信特有字段
    private final String wechatOpenId;

    // 银行卡特有字段
    private final String cardNumber;
    private final String cardHolder;

    public enum PaymentMethod {
        ALIPAY, WECHAT, BANK_CARD
    }

    private PaymentRequest(BuilderBase builder) {
        this.orderId = builder.orderId;
        this.method = builder.method;
        this.amount = builder.amount;
        this.alipayAccount = builder instanceof AlipayBuilder ?
            ((AlipayBuilder) builder).alipayAccount : null;
        this.wechatOpenId = builder instanceof WechatBuilder ?
            ((WechatBuilder) builder).wechatOpenId : null;
        this.cardNumber = builder instanceof BankCardBuilder ?
            ((BankCardBuilder) builder).cardNumber : null;
        this.cardHolder = builder instanceof BankCardBuilder ?
            ((BankCardBuilder) builder).cardHolder : null;
    }

    // ============ Step接口定义 ============

    public interface OrderStep {
        AmountStep orderId(String orderId);
    }

    public interface AmountStep {
        MethodStep amount(double amount);
    }

    public interface MethodStep {
        AlipayStep alipay();
        WechatStep wechat();
        BankCardStep bankCard();
    }

    public interface AlipayStep {
        BuildStep account(String alipayAccount);
    }

    public interface WechatStep {
        BuildStep openId(String wechatOpenId);
    }

    public interface BankCardStep {
        CardHolderStep cardNumber(String cardNumber);
    }

    public interface CardHolderStep {
        BuildStep cardHolder(String cardHolder);
    }

    public interface BuildStep {
        PaymentRequest build();
    }

    // ============ Builder基类 ============

    private static abstract class BuilderBase implements OrderStep, AmountStep, MethodStep {
        protected String orderId;
        protected double amount;
        protected PaymentMethod method;

        @Override
        public AmountStep orderId(String orderId) {
            this.orderId = orderId;
            return this;
        }

        @Override
        public MethodStep amount(double amount) {
            this.amount = amount;
            return this;
        }
    }

    // ============ 具体Builder实现 ============

    private static class AlipayBuilder extends BuilderBase implements AlipayStep, BuildStep {
        private String alipayAccount;

        @Override
        public AlipayStep alipay() {
            this.method = PaymentMethod.ALIPAY;
            return this;
        }

        @Override
        public WechatStep wechat() {
            throw new UnsupportedOperationException();
        }

        @Override
        public BankCardStep bankCard() {
            throw new UnsupportedOperationException();
        }

        @Override
        public BuildStep account(String alipayAccount) {
            this.alipayAccount = alipayAccount;
            return this;
        }

        @Override
        public PaymentRequest build() {
            return new PaymentRequest(this);
        }
    }

    private static class WechatBuilder extends BuilderBase implements WechatStep, BuildStep {
        private String wechatOpenId;

        @Override
        public AlipayStep alipay() {
            throw new UnsupportedOperationException();
        }

        @Override
        public WechatStep wechat() {
            this.method = PaymentMethod.WECHAT;
            return this;
        }

        @Override
        public BankCardStep bankCard() {
            throw new UnsupportedOperationException();
        }

        @Override
        public BuildStep openId(String wechatOpenId) {
            this.wechatOpenId = wechatOpenId;
            return this;
        }

        @Override
        public PaymentRequest build() {
            return new PaymentRequest(this);
        }
    }

    private static class BankCardBuilder extends BuilderBase
            implements BankCardStep, CardHolderStep, BuildStep {
        private String cardNumber;
        private String cardHolder;

        @Override
        public AlipayStep alipay() {
            throw new UnsupportedOperationException();
        }

        @Override
        public WechatStep wechat() {
            throw new UnsupportedOperationException();
        }

        @Override
        public BankCardStep bankCard() {
            this.method = PaymentMethod.BANK_CARD;
            return this;
        }

        @Override
        public CardHolderStep cardNumber(String cardNumber) {
            this.cardNumber = cardNumber;
            return this;
        }

        @Override
        public BuildStep cardHolder(String cardHolder) {
            this.cardHolder = cardHolder;
            return this;
        }

        @Override
        public PaymentRequest build() {
            return new PaymentRequest(this);
        }
    }

    // ============ 统一入口 ============

    public static OrderStep builder() {
        return new UnifiedBuilder();
    }

    private static class UnifiedBuilder extends BuilderBase {
        @Override
        public AlipayStep alipay() {
            AlipayBuilder builder = new AlipayBuilder();
            builder.orderId = this.orderId;
            builder.amount = this.amount;
            return builder.alipay();
        }

        @Override
        public WechatStep wechat() {
            WechatBuilder builder = new WechatBuilder();
            builder.orderId = this.orderId;
            builder.amount = this.amount;
            return builder.wechat();
        }

        @Override
        public BankCardStep bankCard() {
            BankCardBuilder builder = new BankCardBuilder();
            builder.orderId = this.orderId;
            builder.amount = this.amount;
            return builder.bankCard();
        }
    }

    @Override
    public String toString() {
        return "PaymentRequest{" +
                "orderId='" + orderId + '\'' +
                ", method=" + method +
                ", amount=" + amount +
                ", alipayAccount='" + alipayAccount + '\'' +
                ", wechatOpenId='" + wechatOpenId + '\'' +
                ", cardNumber='" + cardNumber + '\'' +
                ", cardHolder='" + cardHolder + '\'' +
                '}';
    }
}

使用示例:

java 复制代码
public class PaymentDemo {

    public static void main(String[] args) {
        // 支付宝支付
        PaymentRequest alipayPayment = PaymentRequest.builder()
                .orderId("ORDER_001")
                .amount(99.99)
                .alipay()
                .account("user@alipay.com")
                .build();

        System.out.println(alipayPayment);

        // 微信支付
        PaymentRequest wechatPayment = PaymentRequest.builder()
                .orderId("ORDER_002")
                .amount(199.99)
                .wechat()
                .openId("wx_openid_123456")
                .build();

        System.out.println(wechatPayment);

        // 银行卡支付
        PaymentRequest bankPayment = PaymentRequest.builder()
                .orderId("ORDER_003")
                .amount(299.99)
                .bankCard()
                .cardNumber("6222021234567890")
                .cardHolder("Zhang San")
                .build();

        System.out.println(bankPayment);
    }
}

5.3 验证增强

在build()方法中添加复杂验证逻辑:

java 复制代码
public class ValidatedUser {

    private final String username;
    private final String password;
    private final String email;
    private final int age;

    private ValidatedUser(Builder builder) {
        this.username = builder.username;
        this.password = builder.password;
        this.email = builder.email;
        this.age = builder.age;
    }

    // ... Step接口定义 ...

    private static class Builder implements UsernameStep, PasswordStep, EmailStep, AgeStep, BuildStep {

        private String username;
        private String password;
        private String email;
        private int age;

        // ... 各步骤实现 ...

        @Override
        public ValidatedUser build() {
            // 用户名验证
            if (username.length() < 3 || username.length() > 20) {
                throw new IllegalArgumentException("用户名长度必须在3-20之间");
            }
            if (!username.matches("^[a-zA-Z0-9_]+$")) {
                throw new IllegalArgumentException("用户名只能包含字母、数字和下划线");
            }

            // 密码验证
            if (password.length() < 8) {
                throw new IllegalArgumentException("密码长度不能少于8位");
            }
            if (!password.matches(".*[A-Z].*")) {
                throw new IllegalArgumentException("密码必须包含至少一个大写字母");
            }
            if (!password.matches(".*[0-9].*")) {
                throw new IllegalArgumentException("密码必须包含至少一个数字");
            }

            // 邮箱验证
            if (!email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
                throw new IllegalArgumentException("邮箱格式不正确");
            }

            // 年龄验证
            if (age < 18 || age > 120) {
                throw new IllegalArgumentException("年龄必须在18-120之间");
            }

            return new ValidatedUser(this);
        }
    }

    public static UsernameStep builder() {
        return new Builder();
    }
}

六、Step Builder vs 其他模式

6.1 对比表格

复制代码
特性对比:
┌────────────────┬──────────────┬──────────────┬──────────────┐
│    特性        │ Step Builder │ 传统Builder  │ 构造函数     │
├────────────────┼──────────────┼──────────────┼──────────────┤
│ 必填参数检查   │ 编译期       │ 运行期       │ 编译期       │
├────────────────┼──────────────┼──────────────┼──────────────┤
│ 可读性         │ ★★★★★       │ ★★★★☆       │ ★★☆☆☆       │
├────────────────┼──────────────┼──────────────┼──────────────┤
│ 类型安全       │ ★★★★★       │ ★★★☆☆       │ ★★★★★       │
├────────────────┼──────────────┼──────────────┼──────────────┤
│ 实现复杂度     │ ★★★★☆       │ ★★☆☆☆       │ ★☆☆☆☆       │
├────────────────┼──────────────┼──────────────┼──────────────┤
│ 扩展性         │ ★★★★★       │ ★★★★☆       │ ★★☆☆☆       │
├────────────────┼──────────────┼──────────────┼──────────────┤
│ IDE支持        │ ★★★★★       │ ★★★★☆       │ ★★★☆☆       │
└────────────────┴──────────────┴──────────────┴──────────────┘

6.2 选择指南

使用Step Builder的场景:

  • ✅ 对象有多个必填参数
  • ✅ 需要编译期保证参数完整性
  • ✅ 构建过程有明确的步骤顺序
  • ✅ API需要高度的类型安全

使用传统Builder的场景:

  • ✅ 大部分参数都是可选的
  • ✅ 参数没有明确的顺序要求
  • ✅ 需要简单实现

使用构造函数的场景:

  • ✅ 参数很少(1-3个)
  • ✅ 所有参数都是必填的
  • ✅ 对象创建非常简单

七、实际生产经验

7.1 Lombok集成

可以使用Lombok减少样板代码:

java 复制代码
import lombok.Builder;
import lombok.Value;

// 注意:Lombok的@Builder不支持Step Builder
// 需要手动实现Step接口

@Value
public class Product {
    String id;
    String name;
    double price;
    String category;

    // 手动实现Step Builder
    public static IdStep builder() {
        return new StepBuilder();
    }

    // Step接口定义...

    private static class StepBuilder implements IdStep, NameStep, PriceStep, CategoryStep, BuildStep {
        private String id;
        private String name;
        private double price;
        private String category;

        // 实现各步骤方法...

        @Override
        public Product build() {
            return new Product(id, name, price, category);
        }
    }
}

7.2 测试友好性

Step Builder模式使测试数据构建更加清晰:

java 复制代码
public class UserTest {

    @Test
    public void testUserCreation() {
        // 测试数据构建清晰明了
        User validUser = User.builder()
                .username("testuser")
                .password("TestPass123")
                .email("test@example.com")
                .age(25)
                .build();

        assertNotNull(validUser);
        assertEquals("testuser", validUser.getUsername());
    }

    @Test
    public void testInvalidEmail() {
        // 编译器强制设置所有必填字段
        assertThrows(IllegalArgumentException.class, () -> {
            User.builder()
                    .username("testuser")
                    .password("TestPass123")
                    .email("invalid-email")  // 无效邮箱
                    .age(25)
                    .build();
        });
    }
}

7.3 性能考虑

Step Builder的性能开销主要来自:

  • 多个接口的实现
  • 对象创建时的类型转换

优化建议:

java 复制代码
// 1. 使用final字段减少内存占用
private static class Builder implements ... {
    private final StringBuilder urlBuilder = new StringBuilder();
    // ...
}

// 2. 对于高频调用,考虑对象池
public class ObjectPooledBuilder {
    private static final ThreadLocal<Builder> POOL =
        ThreadLocal.withInitial(Builder::new);

    public static BuilderStep builder() {
        Builder builder = POOL.get();
        builder.reset();
        return builder;
    }
}

// 3. 延迟验证到build()方法
@Override
public User build() {
    validateAll();  // 只在最后验证一次
    return new User(this);
}

八、常见问题与解决方案

8.1 如何处理可选参数组

java 复制代码
public interface BuildStep {
    // 方案1: 单独的可选参数方法
    BuildStep optionalField1(String value);
    BuildStep optionalField2(String value);

    // 方案2: 配置对象
    BuildStep withOptions(Options options);

    User build();
}

public class Options {
    private String field1;
    private String field2;

    public static Options create() {
        return new Options();
    }

    public Options field1(String value) {
        this.field1 = value;
        return this;
    }

    public Options field2(String value) {
        this.field2 = value;
        return this;
    }
}

8.2 如何支持不可变对象

java 复制代码
@Value  // Lombok注解,生成不可变对象
public class ImmutableUser {
    String username;
    String password;
    String email;

    // Step Builder确保所有必填字段都被设置
    // build()返回不可变对象
}

8.3 如何处理继承

java 复制代码
public class Employee extends Person {

    private final String employeeId;
    private final String department;

    // 继承父类的Step Builder
    public static EmployeeIdStep builder() {
        return new Builder();
    }

    // 扩展父类的Step接口
    public interface EmployeeIdStep extends Person.NameStep {
        DepartmentStep employeeId(String id);
    }

    public interface DepartmentStep {
        Person.BuildStep department(String dept);
    }

    private static class Builder extends Person.Builder
            implements EmployeeIdStep, DepartmentStep {

        private String employeeId;
        private String department;

        @Override
        public DepartmentStep employeeId(String id) {
            this.employeeId = id;
            return this;
        }

        @Override
        public Person.BuildStep department(String dept) {
            this.department = dept;
            return this;
        }

        @Override
        public Employee build() {
            return new Employee(this);
        }
    }
}

九、总结

9.1 核心优势

  1. 编译期安全:在编译时就能发现缺少必填参数的错误
  2. 清晰的API:IDE自动提示引导开发者完成所有步骤
  3. 类型安全:利用类型系统保证调用顺序
  4. 自文档化:代码本身就说明了构建流程

9.2 适用场景总结

复制代码
推荐使用Step Builder的情况:
├─ 对象有3个以上必填参数
├─ 需要严格的参数验证
├─ 构建过程有明确的步骤顺序
├─ 团队希望提高代码质量
└─ 公共API需要防止误用

不推荐使用的情况:
├─ 简单对象(参数少于3个)
├─ 参数都是可选的
├─ 快速原型开发
└─ 性能极度敏感的场景

9.3 最佳实践清单

  • ✅ 为每个必填参数创建独立的Step接口
  • ✅ 将可选参数放在最后的BuildStep中
  • ✅ 在build()方法中进行最终验证
  • ✅ 使用有意义的接口命名(如UsernameStep)
  • ✅ 提供清晰的JavaDoc文档
  • ✅ 考虑使用代码生成工具减少重复代码
  • ❌ 不要在Step方法中进行复杂验证
  • ❌ 不要过度使用(简单对象用普通Builder)
相关推荐
雨中飘荡的记忆1 小时前
设计模式之建造者模式详解
java·设计模式·建造者模式
通义灵码1 小时前
Java 后端开发工程师使用 Qoder 实现面向 API 的运维平台前端开发
java·运维·状态模式
-大头.1 小时前
Spring消息集成:从企业模式到云原生
java·spring·云原生
杀死那个蝈坦1 小时前
Redis 缓存预热
java·开发语言·青少年编程·kotlin·lua
稚辉君.MCA_P8_Java1 小时前
在Java中,将`Short`(包装类)或`short`(基本类型)转换为`int`
java·开发语言
一只乔哇噻1 小时前
java后端工程师+AI大模型进修ing(研一版‖day59)
java·开发语言·算法·语言模型
武子康1 小时前
Java-182 OSS 权限控制实战:ACL / RAM / Bucket Policy 与错误排查
java·数据库·阿里云·云计算·oss·fastdfs·fdfs
深圳佛手1 小时前
Consul热更新的原理与实现
java·linux·网络
XL's妃妃1 小时前
Java缓存全解析:概念、分类、Guava Cache、算法及对比
java·缓存·guava