Builder

Constructs complex objects step by step, separating the construction algorithm from its representation.

Context

A class has 12 optional parameters (timeouts, headers, retries, proxy...). Its constructor is unreadable and you never remember the order.

Problem
  • Telescoping constructors that are impossible to read.
  • Need to validate the object before instantiating it.
Solution

A Builder accumulates configuration with chainable methods and, at the end, Build() validates and produces the immutable object.

#Example in C# — Fluent Builder

public sealed class HttpClientOptions
{
    public Uri BaseAddress { get; init; } = default!;
    public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(30);
    public IReadOnlyDictionary<string, string> Headers { get; init; } = new Dictionary<string, string>();
}

public class HttpClientOptionsBuilder
{
    private Uri? _base;
    private TimeSpan _timeout = TimeSpan.FromSeconds(30);
    private readonly Dictionary<string, string> _headers = new();

    public HttpClientOptionsBuilder BaseAddress(string url) { _base = new Uri(url); return this; }
    public HttpClientOptionsBuilder Timeout(TimeSpan t)     { _timeout = t; return this; }
    public HttpClientOptionsBuilder Header(string k, string v) { _headers[k] = v; return this; }

    public HttpClientOptions Build()
    {
        if (_base is null) throw new InvalidOperationException("BaseAddress requerido");
        return new HttpClientOptions { BaseAddress = _base, Timeout = _timeout, Headers = _headers };
    }
}

// Uso
var opts = new HttpClientOptionsBuilder()
    .BaseAddress("https://api.example.com")
    .Timeout(TimeSpan.FromSeconds(10))
    .Header("X-Api-Key", "secret")
    .Build();
When NOT to use it
  • When the object has 2-3 parameters: use the constructor or a record.
  • When data comes from a DTO/JSON: deserialize directly.
Tradeoffs
Pro Con
Prose-like readability More boilerplate code
Centralized validation Temporary mutable state in the builder
Allows building variants with the same API Refactoring the object requires synchronizing the builder

#Variants

  • Director (classic GoF, orchestrates builders).
  • Step Builder (each step returns a different interface, enforcing order).

#creational #gof #fluent