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 = 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.