CreationalC#verifiedVerified
Builder Pattern in C#
Separates the construction of a complex object from its representation, allowing the same construction process to produce different results.
How to Implement the Builder Pattern in C#
1Step 1: Define the product
public class House
{
public int Floors { get; set; }
public bool HasGarage { get; set; }
public bool HasPool { get; set; }
public string? RoofType { get; set; }
public override string ToString() =>
$"House(Floors={Floors}, Garage={HasGarage}, " +
$"Pool={HasPool}, Roof={RoofType})";
}2Step 2: Builder with fluent interface
public class HouseBuilder
{
private readonly House _house = new();
public HouseBuilder SetFloors(int floors)
{
_house.Floors = floors;
return this;
}
public HouseBuilder AddGarage()
{
_house.HasGarage = true;
return this;
}
public HouseBuilder AddPool()
{
_house.HasPool = true;
return this;
}
public HouseBuilder SetRoof(string roofType)
{
_house.RoofType = roofType;
return this;
}3Step 3: Build returns the finished product
public House Build() => _house;
}
// Usage:
// var house = new HouseBuilder()
// .SetFloors(2)
// .AddGarage()
// .SetRoof("Gable")
// .Build();// [step] Define an immutable product with required members
public sealed record HttpRequest
{
public required string Method { get; init; }
public required Uri Url { get; init; }
public IReadOnlyDictionary<string, string> Headers { get; init; }
= new Dictionary<string, string>();
public string? Body { get; init; }
public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(30);
public int MaxRetries { get; init; }
}
// [step] Fluent builder with validation
public sealed class HttpRequestBuilder
{
private string _method = "GET";
private Uri? _url;
private readonly Dictionary<string, string> _headers = [];
private string? _body;
private TimeSpan _timeout = TimeSpan.FromSeconds(30);
private int _maxRetries;
public HttpRequestBuilder WithMethod(string method)
{
ArgumentException.ThrowIfNullOrWhiteSpace(method);
_method = method.ToUpperInvariant();
return this;
}
public HttpRequestBuilder WithUrl(string url)
{
_url = new Uri(url);
return this;
}
public HttpRequestBuilder WithHeader(string key, string value)
{
_headers[key] = value;
return this;
}
public HttpRequestBuilder WithBearerToken(string token)
{
_headers["Authorization"] = $"Bearer {token}";
return this;
}
public HttpRequestBuilder WithJsonBody(string json)
{
_body = json;
_headers["Content-Type"] = "application/json";
return this;
}
public HttpRequestBuilder WithTimeout(TimeSpan timeout)
{
ArgumentOutOfRangeException.ThrowIfLessThan(
timeout.TotalMilliseconds, 1);
_timeout = timeout;
return this;
}
public HttpRequestBuilder WithRetries(int count)
{
ArgumentOutOfRangeException.ThrowIfNegative(count);
_maxRetries = count;
return this;
}
// [step] Build with validation
public HttpRequest Build()
{
if (_url is null)
throw new InvalidOperationException("URL is required");
if (_method is "POST" or "PUT" or "PATCH" && _body is null)
throw new InvalidOperationException(
$"{_method} requires a body");
return new HttpRequest
{
Method = _method,
Url = _url,
Headers = _headers.AsReadOnly(),
Body = _body,
Timeout = _timeout,
MaxRetries = _maxRetries,
};
}
}
// [step] Director for common configurations
public static class HttpRequestDirector
{
public static HttpRequest CreateGetRequest(string url) =>
new HttpRequestBuilder()
.WithMethod("GET")
.WithUrl(url)
.Build();
public static HttpRequest CreateAuthenticatedPost(
string url, string body, string token) =>
new HttpRequestBuilder()
.WithMethod("POST")
.WithUrl(url)
.WithJsonBody(body)
.WithBearerToken(token)
.WithRetries(3)
.Build();
}Builder Pattern Architecture
hourglass_empty
Rendering diagram...
lightbulb
Builder Pattern in the Real World
“Consider ordering a custom sandwich at a deli. You tell the sandwich artist (builder) each step — bread type, protein, toppings, sauce — and they assemble it in the right order. You don’t need to know how to layer ingredients properly; you just specify what you want, and the builder hands you a finished sandwich.”