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 = builder.headers;
}
static class Builder {
private String url;
private String method = "GET";
private 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 k, String v) { this.headers.put(k, v); return this; }
HttpRequest build() { 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 { 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.