Skip to main content

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.