Home/Design Patterns/Builder Design Pattern

Builder Design Pattern

🎯 Explain Like I'm 5...

Imagine you're making a burger at a restaurant! You don't get the burger all at once - you build it step by step!

🍔 Building a Burger Step by Step:

  • Step 1: Start with a bun 🍞
  • Step 2: Add a patty 🥩
  • Step 3: Add cheese 🧀 (if you want!)
  • Step 4: Add lettuce 🥬 (if you want!)
  • Step 5: Add tomatoes 🍅 (if you want!)
  • Step 6: Add pickles 🥒 (if you want!)
  • Step 7: Put the top bun on, and tada! 🎉

The Builder pattern lets you choose what to add, just like customizing your burger!

🚀 Why Use the Builder Pattern?

  • When you have many optional parts (like burger toppings)
  • When creating an object step by step makes more sense
  • When you want to create different versions of the same thing
  • When constructor has too many parameters (confusing!)

📋 Pattern Purpose

The Builder pattern separates the construction of a complex object from its representation, allowing the same construction process to create different representations. It's perfect for creating objects with many optional parameters or when the construction process is complex.

💻 Java Implementations

Example 1: House Builder (Basic Builder)

Building a house with walls, roof, windows, and doors. Shows the classic Builder pattern structure.

House.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// The House class - the product we're building
public class House {
// Required parameters
private final String foundation;
private final String structure;
// Optional parameters
private final String roof;
private final int windows;
private final int doors;
private final boolean hasGarage;
private final boolean hasGarden;
private final boolean hasSwimmingPool;
// Private constructor - can only be called by Builder
private House(HouseBuilder builder) {
this.foundation = builder.foundation;
this.structure = builder.structure;
this.roof = builder.roof;
this.windows = builder.windows;
this.doors = builder.doors;
this.hasGarage = builder.hasGarage;
this.hasGarden = builder.hasGarden;
this.hasSwimmingPool = builder.hasSwimmingPool;
}
// Static nested Builder class
public static class HouseBuilder {
// Required parameters
private final String foundation;
private final String structure;
// Optional parameters - initialized to default values
private String roof = "Standard Roof";
private int windows = 4;
private int doors = 1;
private boolean hasGarage = false;
private boolean hasGarden = false;
private boolean hasSwimmingPool = false;
// Builder constructor with required parameters
public HouseBuilder(String foundation, String structure) {
this.foundation = foundation;
this.structure = structure;
}
// Setter methods for optional parameters - return 'this' for chaining
public HouseBuilder roof(String roof) {
this.roof = roof;
return this;
}
public HouseBuilder windows(int windows) {
this.windows = windows;
return this;
}
public HouseBuilder doors(int doors) {
this.doors = doors;
return this;
}
public HouseBuilder garage(boolean hasGarage) {
this.hasGarage = hasGarage;
return this;
}
public HouseBuilder garden(boolean hasGarden) {
this.hasGarden = hasGarden;
return this;
}
public HouseBuilder swimmingPool(boolean hasSwimmingPool) {
this.hasSwimmingPool = hasSwimmingPool;
return this;
}
// Build method - creates and returns the final House object
public House build() {
return new House(this);
}
}
@Override
public String toString() {
return "House{" +
"foundation='" + foundation + '\'' +
", structure='" + structure + '\'' +
", roof='" + roof + '\'' +
", windows=" + windows +
", doors=" + doors +
", hasGarage=" + hasGarage +
", hasGarden=" + hasGarden +
", hasSwimmingPool=" + hasSwimmingPool +
'}';
}
public static void main(String[] args) {
// Building a simple house with only required parameters
House simpleHouse = new House.HouseBuilder("Concrete", "Wood")
.build();
System.out.println("Simple House: " + simpleHouse);
// Building a luxury house with all features
House luxuryHouse = new House.HouseBuilder("Reinforced Concrete", "Brick")
.roof("Tile Roof")
.windows(12)
.doors(3)
.garage(true)
.garden(true)
.swimmingPool(true)
.build();
System.out.println("\nLuxury House: " + luxuryHouse);
// Building a custom house - choose only what you want!
House customHouse = new House.HouseBuilder("Stone", "Brick")
.windows(8)
.doors(2)
.garden(true)
.build();
System.out.println("\nCustom House: " + customHouse);
}
}

Example 2: Pizza Builder (Fluent Builder)

Building a customizable pizza with method chaining. Demonstrates fluent interface design for better readability.

Pizza.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import java.util.ArrayList;
import java.util.List;
// Pizza class with fluent builder interface
public class Pizza {
// Enum for pizza size
public enum Size {
SMALL, MEDIUM, LARGE, EXTRA_LARGE
}
// Enum for crust type
public enum Crust {
THIN, REGULAR, THICK, STUFFED
}
// Required field
private final Size size;
// Optional fields
private final Crust crust;
private final boolean cheese;
private final boolean pepperoni;
private final boolean mushrooms;
private final boolean onions;
private final boolean olives;
private final boolean extraCheese;
private final List<String> customToppings;
// Private constructor
private Pizza(PizzaBuilder builder) {
this.size = builder.size;
this.crust = builder.crust;
this.cheese = builder.cheese;
this.pepperoni = builder.pepperoni;
this.mushrooms = builder.mushrooms;
this.onions = builder.onions;
this.olives = builder.olives;
this.extraCheese = builder.extraCheese;
this.customToppings = builder.customToppings;
}
// Static Builder class with fluent interface
public static class PizzaBuilder {
// Required parameter
private final Size size;
// Optional parameters with default values
private Crust crust = Crust.REGULAR;
private boolean cheese = true; // Every pizza has cheese by default!
private boolean pepperoni = false;
private boolean mushrooms = false;
private boolean onions = false;
private boolean olives = false;
private boolean extraCheese = false;
private List<String> customToppings = new ArrayList<>();
// Constructor with required parameters
public PizzaBuilder(Size size) {
this.size = size;
}
// Fluent methods for setting options
public PizzaBuilder crust(Crust crust) {
this.crust = crust;
return this;
}
public PizzaBuilder noCheese() {
this.cheese = false;
return this;
}
public PizzaBuilder addPepperoni() {
this.pepperoni = true;
return this;
}
public PizzaBuilder addMushrooms() {
this.mushrooms = true;
return this;
}
public PizzaBuilder addOnions() {
this.onions = true;
return this;
}
public PizzaBuilder addOlives() {
this.olives = true;
return this;
}
public PizzaBuilder extraCheese() {
this.extraCheese = true;
return this;
}
public PizzaBuilder addCustomTopping(String topping) {
this.customToppings.add(topping);
return this;
}
// Build method creates the Pizza
public Pizza build() {
return new Pizza(this);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Pizza {\n");
sb.append(" Size: ").append(size).append("\n");
sb.append(" Crust: ").append(crust).append("\n");
sb.append(" Toppings:\n");
if (cheese) sb.append(" - Cheese\n");
if (extraCheese) sb.append(" - Extra Cheese\n");
if (pepperoni) sb.append(" - Pepperoni\n");
if (mushrooms) sb.append(" - Mushrooms\n");
if (onions) sb.append(" - Onions\n");
if (olives) sb.append(" - Olives\n");
if (!customToppings.isEmpty()) {
sb.append(" Custom Toppings:\n");
for (String topping : customToppings) {
sb.append(" - ").append(topping).append("\n");
}
}
sb.append("}");
return sb.toString();
}
public static void main(String[] args) {
// Simple cheese pizza
Pizza cheesePizza = new Pizza.PizzaBuilder(Size.MEDIUM)
.build();
System.out.println("=== Cheese Pizza ===");
System.out.println(cheesePizza);
// Deluxe pizza with everything!
Pizza deluxePizza = new Pizza.PizzaBuilder(Size.LARGE)
.crust(Crust.THICK)
.extraCheese()
.addPepperoni()
.addMushrooms()
.addOnions()
.addOlives()
.build();
System.out.println("\n=== Deluxe Pizza ===");
System.out.println(deluxePizza);
// Custom pizza with special toppings
Pizza customPizza = new Pizza.PizzaBuilder(Size.EXTRA_LARGE)
.crust(Crust.THIN)
.addPepperoni()
.addCustomTopping("Pineapple")
.addCustomTopping("Jalapeños")
.addCustomTopping("BBQ Chicken")
.build();
System.out.println("\n=== Custom Pizza ===");
System.out.println(customPizza);
// Vegan pizza (no cheese!)
Pizza veganPizza = new Pizza.PizzaBuilder(Size.MEDIUM)
.noCheese()
.addMushrooms()
.addOnions()
.addOlives()
.addCustomTopping("Vegan Cheese")
.addCustomTopping("Artichokes")
.build();
System.out.println("\n=== Vegan Pizza ===");
System.out.println(veganPizza);
}
}

Example 3: Computer Builder (Complex Builder)

Building a computer with required and optional components. Shows validation and required vs optional parameters.

Computer.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// Computer class with validation in builder
public class Computer {
// Required components
private final String cpu;
private final int ramGB;
private final int storageGB;
// Optional components
private final String gpu;
private final boolean hasSSD;
private final boolean hasWiFi;
private final boolean hasBluetooth;
private final int usbPorts;
private final String operatingSystem;
// Private constructor
private Computer(ComputerBuilder builder) {
this.cpu = builder.cpu;
this.ramGB = builder.ramGB;
this.storageGB = builder.storageGB;
this.gpu = builder.gpu;
this.hasSSD = builder.hasSSD;
this.hasWiFi = builder.hasWiFi;
this.hasBluetooth = builder.hasBluetooth;
this.usbPorts = builder.usbPorts;
this.operatingSystem = builder.operatingSystem;
}
// Getter methods
public String getCpu() { return cpu; }
public int getRamGB() { return ramGB; }
public int getStorageGB() { return storageGB; }
public String getGpu() { return gpu; }
public boolean hasSSD() { return hasSSD; }
public boolean hasWiFi() { return hasWiFi; }
public boolean hasBluetooth() { return hasBluetooth; }
public int getUsbPorts() { return usbPorts; }
public String getOperatingSystem() { return operatingSystem; }
// Static Builder class
public static class ComputerBuilder {
// Required parameters
private final String cpu;
private final int ramGB;
private final int storageGB;
// Optional parameters with default values
private String gpu = "Integrated Graphics";
private boolean hasSSD = false;
private boolean hasWiFi = true;
private boolean hasBluetooth = false;
private int usbPorts = 2;
private String operatingSystem = "None";
// Constructor requires essential components
public ComputerBuilder(String cpu, int ramGB, int storageGB) {
this.cpu = cpu;
this.ramGB = ramGB;
this.storageGB = storageGB;
}
// Optional component methods
public ComputerBuilder gpu(String gpu) {
this.gpu = gpu;
return this;
}
public ComputerBuilder ssd(boolean hasSSD) {
this.hasSSD = hasSSD;
return this;
}
public ComputerBuilder wifi(boolean hasWiFi) {
this.hasWiFi = hasWiFi;
return this;
}
public ComputerBuilder bluetooth(boolean hasBluetooth) {
this.hasBluetooth = hasBluetooth;
return this;
}
public ComputerBuilder usbPorts(int usbPorts) {
this.usbPorts = usbPorts;
return this;
}
public ComputerBuilder operatingSystem(String os) {
this.operatingSystem = os;
return this;
}
// Build method with validation
public Computer build() {
// Validate before building
if (ramGB < 4) {
throw new IllegalStateException("RAM must be at least 4GB");
}
if (storageGB < 128) {
throw new IllegalStateException("Storage must be at least 128GB");
}
if (usbPorts < 0 || usbPorts > 10) {
throw new IllegalStateException("USB ports must be between 0 and 10");
}
// If SSD is true and storage is large, recommend more RAM
if (hasSSD && storageGB > 512 && ramGB < 16) {
System.out.println("Warning: Consider upgrading RAM for better performance!");
}
return new Computer(this);
}
}
@Override
public String toString() {
return "Computer {\n" +
" CPU: " + cpu + "\n" +
" RAM: " + ramGB + " GB\n" +
" Storage: " + storageGB + " GB " + (hasSSD ? "(SSD)" : "(HDD)") + "\n" +
" GPU: " + gpu + "\n" +
" WiFi: " + (hasWiFi ? "Yes" : "No") + "\n" +
" Bluetooth: " + (hasBluetooth ? "Yes" : "No") + "\n" +
" USB Ports: " + usbPorts + "\n" +
" OS: " + operatingSystem + "\n" +
"}";
}
public static void main(String[] args) {
// Basic computer for office work
Computer officePC = new Computer.ComputerBuilder("Intel i5", 8, 256)
.ssd(true)
.operatingSystem("Windows 11")
.build();
System.out.println("=== Office PC ===");
System.out.println(officePC);
// Gaming computer with all features
Computer gamingPC = new Computer.ComputerBuilder("AMD Ryzen 9", 32, 2000)
.gpu("NVIDIA RTX 4090")
.ssd(true)
.wifi(true)
.bluetooth(true)
.usbPorts(8)
.operatingSystem("Windows 11 Pro")
.build();
System.out.println("\n=== Gaming PC ===");
System.out.println(gamingPC);
// Development workstation
Computer devWorkstation = new Computer.ComputerBuilder("Intel i9", 64, 4000)
.gpu("NVIDIA RTX 4070")
.ssd(true)
.wifi(true)
.bluetooth(true)
.usbPorts(6)
.operatingSystem("Ubuntu Linux")
.build();
System.out.println("\n=== Developer Workstation ===");
System.out.println(devWorkstation);
// Budget laptop
Computer budgetLaptop = new Computer.ComputerBuilder("Intel i3", 8, 512)
.ssd(true)
.wifi(true)
.bluetooth(true)
.usbPorts(3)
.operatingSystem("Chrome OS")
.build();
System.out.println("\n=== Budget Laptop ===");
System.out.println(budgetLaptop);
// This will throw an exception - too little RAM!
try {
Computer invalidPC = new Computer.ComputerBuilder("Intel i5", 2, 256)
.build();
} catch (IllegalStateException e) {
System.out.println("\n=== Error Creating Invalid PC ===");
System.out.println("Error: " + e.getMessage());
}
}
}

🌍 Real-World Examples

  • 1️⃣StringBuilder/StringBuffer: Building strings efficiently in Java
  • 2️⃣HTTP Request Builders: Libraries like OkHttp, Apache HttpClient
  • 3️⃣Query Builders: SQL query builders in ORMs (Hibernate, JPA)
  • 4️⃣UI Builders: Android AlertDialog.Builder, Notification.Builder
  • 5️⃣Document Builders: XML/JSON document builders

⚡ When to Use Builder Pattern

  • Too many constructor parameters (more than 4-5)
  • Many optional parameters in object creation
  • Object construction is complex or multi-step
  • Need immutable objects with many fields
  • Want to prevent inconsistent object state during construction

✅ Benefits

  • Readable code: Clear and fluent API
  • Flexible construction: Choose what to include
  • Immutability: Objects are immutable once built
  • Validation: Can validate before building final object
  • No telescoping constructors: Avoid multiple overloaded constructors

🔑 Key Implementation Points

  • 1️⃣Use static nested Builder class inside the target class
  • 2️⃣Builder has same fields as target class
  • 3️⃣Builder methods return 'this' for method chaining
  • 4️⃣Target class constructor is private, accepts Builder
  • 5️⃣build() method creates and returns the final object
  • 6️⃣Optional: Validate in build() method before creating object

💪 Practice Scenarios

  • Create a Builder for a User class with username, email, phone, address
  • Build an Email class with to, from, subject, body, attachments
  • Design a Car builder with make, model, year, color, features
  • Create a Resume builder with sections like education, experience, skills
  • Build a RestaurantOrder with items, customizations, delivery info