Builder
Overview
Separate the construction of a complex object from its representation.
When to use
- You need to build objects step by step.
- You want readable, fluent creation for many optional fields.
Java example
class HttpRequest {
final String url;
final String method;
final Map<String, String> headers;
private HttpRequest(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = Map.copyOf(builder.headers);
}
static class Builder {
private String url;
private String method = "GET";
private final Map<String, String> headers = new HashMap<>();
Builder url(String url) {
this.url = url;
return this;
}
Builder method(String method) {
this.method = method;
return this;
}
Builder header(String key, String value) {
this.headers.put(key, value);
return this;
}
HttpRequest build() {
if (url == null || url.isBlank()) {
throw new IllegalStateException("url is required");
}
return new HttpRequest(this);
}
}
}
TypeScript example
class HttpRequest {
constructor(
readonly url: string,
readonly method: string,
readonly headers: Record<string, string>,
) {}
}
class HttpRequestBuilder {
private url = '';
private method = 'GET';
private headers: Record<string, string> = {};
setUrl(url: string): this {
this.url = url;
return this;
}
setMethod(method: string): this {
this.method = method;
return this;
}
addHeader(key: string, value: string): this {
this.headers[key] = value;
return this;
}
build(): HttpRequest {
if (!this.url) {
throw new Error('url is required');
}
return new HttpRequest(this.url, this.method, { ...this.headers });
}
}
Pros and cons
Pros:
- Clear construction for complex objects.
- Avoids telescoping constructors.
Cons:
- More boilerplate.
- Can be overused for simple objects.
Common pitfalls
- Skipping required fields validation.
- Creating builders for trivial objects.