欢迎光临
我们一直在努力

StepBuilder模式详解

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

一、什么是Step Builder模式

1.1 传统Builder模式的局限性

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

传统Builder的问题示例:

// 传统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 简单示例:用户注册

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 +
'}';
}
}

使用示例:

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

类型安全的关键:

  • 接口链:每个步骤返回不同的接口类型
  • 单一实现:Builder类实现所有接口
  • 方法可见性:每个接口只暴露特定方法
  • 编译期检查:IDE和编译器强制按顺序调用
  • 三、实战案例:HTTP请求构建器

    3.1 场景分析

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

    3.2 完整实现

    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; }
    }

    使用示例:

    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改进它:

    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);
    }
    }

    使用示例:

    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增强

    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:

    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();
    }
    }

    使用示例:

    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

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

    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 + '\\'' +
    '}';
    }
    }

    使用示例:

    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()方法中添加复杂验证逻辑:

    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减少样板代码:

    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模式使测试数据构建更加清晰:

    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的性能开销主要来自:

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

    优化建议:

    // 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 如何处理可选参数组

    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 如何支持不可变对象

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

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

    8.3 如何处理继承

    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 核心优势

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

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

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

    9.3 最佳实践清单

    • ✅ 为每个必填参数创建独立的Step接口
    • ✅ 将可选参数放在最后的BuildStep中
    • ✅ 在build()方法中进行最终验证
    • ✅ 使用有意义的接口命名(如UsernameStep)
    • ✅ 提供清晰的JavaDoc文档
    • ✅ 考虑使用代码生成工具减少重复代码
    • ❌ 不要在Step方法中进行复杂验证
    • ❌ 不要过度使用(简单对象用普通Builder)
    赞(0)
    未经允许不得转载:171主机测评 » StepBuilder模式详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址