Creational Pattern

Builder Pattern

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

12 min readHigh Priority

1What is Builder Pattern?

Real-World Analogy
Ordering at Subway

You build your sandwich step by step: choose bread, add proteins, vegetables, sauces. The same process creates vastly different sandwiches. You don't get a pre-made sandwich - you construct it piece by piece.

Building a House

A house is built in stages: foundation, walls, roof, interiors. The same construction process can build a wooden cabin or a brick mansion. The builder knows the steps, but the result varies.

Builder is a creational pattern that lets you construct complex objectsstep by step. It allows you to produce different types and representations of an object using the same construction code. Especially useful when an object has many optional parameters.

The Telescoping Constructor Problem

Without Builder
// Telescoping constructor
new Pizza(size, cheese, pepperoni, 
          bacon, mushrooms, onions,
          olives, null, null, null);
          
// Which parameter is which?
// Many nulls for optional params
// Hard to read and maintain
With Builder
// Fluent builder
new Pizza.Builder("Large")
    .addCheese()
    .addPepperoni()
    .addMushrooms()
    .build();
    
// Clear, readable
// Only set what you need

2Two Builder Variants

GoF Builder (Classic)
Has a Director that orchestrates the building process. Builder interface with multiple concrete builders. Used when construction steps are fixed.
Director
  └── Builder (interface)
       ├── ConcreteBuilder1
       └── ConcreteBuilder2
Fluent Builder (Modern)
No Director. Builder as inner class with method chaining. More flexible, commonly used for objects with many optional parameters.
Product.builder()
    .setA(...)
    .setB(...)
    .build();
Which to Use?

Fluent Builder is more common in modern codebases. Use it for objects with many optional parameters (like configuration objects, HTTP requests, SQL queries). Use GoF Builder when you have multiple representations of the same construction process.

3Implementation

Fluent Builder - HTTP Request
// ========== Product ==========
public class HttpRequest {
    private final String url;
    private final String method;
    private final Map<String, String> headers;
    private final String body;
    private final int timeout;
    private final boolean followRedirects;
    
    // Private constructor - only Builder can create
    private HttpRequest(Builder builder) {
        this.url = builder.url;
        this.method = builder.method;
        this.headers = builder.headers;
        this.body = builder.body;
        this.timeout = builder.timeout;
        this.followRedirects = builder.followRedirects;
    }
    
    // Getters...
    public String getUrl() { return url; }
    public String getMethod() { return method; }
    
    @Override
    public String toString() {
        return method + " " + url + " (timeout=" + timeout + "ms)";
    }
    
    // ========== Static Builder Class ==========
    public static class Builder {
        // Required parameters
        private final String url;
        
        // Optional parameters with defaults
        private String method = "GET";
        private Map<String, String> headers = new HashMap<>();
        private String body = null;
        private int timeout = 30000;
        private boolean followRedirects = true;
        
        // Constructor with required params
        public Builder(String url) {
            this.url = url;
        }
        
        // Fluent setters - return this for chaining
        public Builder method(String method) {
            this.method = method;
            return this;
        }
        
        public Builder header(String key, String value) {
            this.headers.put(key, value);
            return this;
        }
        
        public Builder body(String body) {
            this.body = body;
            return this;
        }
        
        public Builder timeout(int ms) {
            this.timeout = ms;
            return this;
        }
        
        public Builder followRedirects(boolean follow) {
            this.followRedirects = follow;
            return this;
        }
        
        // Build method creates the immutable object
        public HttpRequest build() {
            // Validation can happen here
            if (url == null || url.isEmpty()) {
                throw new IllegalStateException("URL is required");
            }
            return new HttpRequest(this);
        }
    }
}

// ========== Usage ==========
public class Main {
    public static void main(String[] args) {
        // Simple GET request
        HttpRequest get = new HttpRequest.Builder("https://api.example.com/users")
            .build();
        System.out.println(get);
        
        // Complex POST request
        HttpRequest post = new HttpRequest.Builder("https://api.example.com/users")
            .method("POST")
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer token123")
            .body("{\"name\": \"John\"}")
            .timeout(5000)
            .followRedirects(false)
            .build();
        System.out.println(post);
    }
}
Output:
GET https://api.example.com/users (timeout=30000ms)
POST https://api.example.com/users (timeout=5000ms)

4Benefits and Drawbacks

Benefits
  • Avoids telescoping constructors
  • Creates immutable objects
  • Readable, self-documenting code
  • Easy to add new optional params
  • Validation before object creation
Drawbacks
  • More code to write
  • Need separate Builder class
  • Overkill for simple objects
  • Requires discipline to maintain
Use Lombok for Java

In Java, use @Builder annotation from Lombok to auto-generate builder code. Saves boilerplate while keeping all benefits.

5Interview Follow-up Questions

Interview Follow-up Questions

Common follow-up questions interviewers ask

6Key Takeaways

1Builder constructs complex objects step by step.
2Solves the telescoping constructor problem.
3Two variants: GoF (with Director) and Fluent (method chaining).
4Creates immutable objects with clear, readable code.
5Required params in constructor, optional via setters.
6Use for: config objects, HTTP requests, queries, DTOs.