Builder Pattern
Shows up when designing things like HTTP requests, configuration objects, etc. Instead of a ctor with 10 parameters where half are null, you build the object incrementally, e.g.,
public class HttpRequest
{
public string? Url { get; private set; }
public string? Method { get; private set; }
public Dictionary<string, string> Headers { get; private set; }
public string? Body { get; private set; }
private HttpRequest() {}
public class Builder
{
private readonly HttpRequest _request = new();
public Builder Url(string url) { ... }
public Builder Method(string method) { ... }
public Builder Body(string body) { ... }
public Builder Header(string key, string value)
{
_request.Headers ??= new Dictionary<string, string>();
_request.Headers[key] = value;
return this;
}
public HttpRequest Build()
{
if (string.IsNullOrWhiteSpace(_request.Url))
throw new InvalidOperationException("URL is required");
return request;
}
}
}
… with usage like:
var request new HttpRequest.Builder()
.Url("https://foo.com")
.Method("GET")
.Build();
The builder pattern is useful for immutable data types, where specifying all of
the parameters in the ctor would prove tedious. In the
example above, Builder has access to the private HttpRequest ctor; once
Builder.Build() is called, the client has a HttpRequest whose properties
like Url cannot be mutated.
The builder pattern can be a sign of violating the Single Responsibility Principle . If there are parameters that you’re always passing in conjunction, refactor those to a class and pass an instance of the new class instead.
Config Object Pattern
Another technique for avoiding long constructors is having a configuration
object. For example, a WebContents in Chromium has (comments omitted for
brevity):
class WebContents : public PageNavigator, public base::SupportsUserData {
public:
struct CreateParams {
explicit CreateParams(
BrowserContext* context,
base::Location creator_location = base::Location::Current());
CreateParams(
BrowserContext* context,
scoped_refptr<SiteInstance> site,
base::Location creator_location = base::Location::Current());
CreateParams(const CreateParams& other);
~CreateParams();
raw_ptr<BrowserContext> browser_context;
scoped_refptr<SiteInstance> site_instance;
GlobalRenderFrameHostId opener_id;
bool opener_suppressed = false;
bool opened_by_another_window = false;
// ... 19 other properties
};
static std::unique_ptr<WebContents> Create(const CreateParams& params);
private:
friend class WebContentsImpl;
WebContents() = default;
};
… so that usage is of the form:
std::unique_ptr<WebContents> web_contents(
WebContents::Create(WebContents::CreateParams(browser_context)));
References
- Design Patterns | Hello Interview Low Level Design. www.hellointerview.com . Accessed Sep 16, 2026.
- web_contents.h - Chromium Code Search. source.chromium.org . Accessed Sep 21, 2026.
- object oriented - When should the builder design pattern be used? - Software Engineering Stack Exchange. softwareengineering.stackexchange.com . Accessed Sep 21, 2026.