Type-Safe Step Builder Pattern
Enforce required fields at compile time with a step builder: each step returns the next interface.
public class StepBuilderDemo {
// The target object
record HttpRequest(
String method,
String url,
java.util.Map<String, String> headers,
String body,
int timeoutMs
) {}
// Step interfaces — enforces order at compile time
interface MethodStep { UrlStep method(String method); }
interface UrlStep { BuildStep url(String url); }
interface BuildStep {
BuildStep header(String key, String value);
BuildStep body(String body);
BuildStep timeout(int ms);
HttpRequest build();
}
// Single implementation
static class HttpRequestBuilder implements MethodStep, UrlStep, BuildStep {
private String method;
private String url;
private final java.util.Map<String, String> headers = new java.util.LinkedHashMap<>();
private String body;
private int timeoutMs = 30_000;
private HttpRequestBuilder() {}
static MethodStep create() { return new HttpRequestBuilder(); }
@Override
public UrlStep method(String method) {
this.method = method;
return this;
}
@Override
public BuildStep url(String url) {
this.url = url;
return this;
}
@Override
public BuildStep header(String key, String value) {
headers.put(key, value);
return this;
}
@Override
public BuildStep body(String body) {
this.body = body;
return this;
}
@Override
public BuildStep timeout(int ms) {
this.timeoutMs = ms;
return this;
}
@Override
public HttpRequest build() {
return new HttpRequest(method, url,
java.util.Collections.unmodifiableMap(headers), body, timeoutMs);
}
}
public static void main(String[] args) {
// Compile-time safety: must call method() → url() → then optional steps
HttpRequest get = HttpRequestBuilder.create()
.method("GET")
.url("https://api.example.com/users")
.header("Accept", "application/json")
.timeout(5000)
.build();
HttpRequest post = HttpRequestBuilder.create()
.method("POST")
.url("https://api.example.com/users")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer token123")
.body("{\"name\": \"Alice\"}")
.build();
System.out.println(get);
System.out.println(post);
// This WON'T compile — enforces order:
// HttpRequestBuilder.create().url("...");
// HttpRequestBuilder.create().method("GET").build();
}
}Use Cases
- Enforcing required fields at compile time
- Fluent API design with mandatory steps
- Complex object construction with validation
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Builder Pattern — Fluent Object Construction
Implement the Builder pattern for complex objects with validation, immutability, and method chaining.
Best for: Constructing complex objects with many optional parameters
Singleton Pattern — Thread-Safe Approaches
Implement thread-safe singletons in Java: enum, holder class, double-checked locking, and eager init.
Best for: Application-wide configuration managers
Strategy Pattern with Lambdas
Implement the Strategy pattern using interfaces and Java lambdas for flexible algorithm selection.
Best for: Swappable pricing or discount algorithms
Factory Method Pattern with Registry
Implement the Factory pattern using a registry map for extensible object creation without switch statements.
Best for: Extensible object creation in plugin architectures