Middle
What is the advantage of the Builder design pattern compared to a regular constructor?
sobes.tech AI
Answer from AI
The Builder pattern offers the following advantages over a regular constructor:
- Improved readability and flexibility: When there are many optional parameters, a constructor can become bulky and hard to read. Builder allows constructing an object step-by-step, assigning values to fields using methods named according to the fields' purpose.
- Construction safety: Unlike a constructor with many parameters, where it's easy to confuse the order of arguments, in Builder each method is responsible for setting a specific field.
- Support for changing requirements: Adding new optional parameters in the future does not break existing code that uses Builder. For a constructor, new overloaded constructors would need to be created or the existing one changed, which could lead to compatibility issues.
- Fewer constructors: Builder eliminates the need for multiple overloaded constructors required to handle different parameter combinations.
Example of using Builder:
// Class we want to build
public class Meal {
private final String mainCourse;
private final String sideDish;
private final String beverage;
private final String dessert;
private Meal(Builder builder) {
this.mainCourse = builder.mainCourse;
this.sideDish = builder.sideDish;
this.beverage = builder.beverage;
this.dessert = builder.dessert;
}
// Static nested Builder class
public static class Builder {
private String mainCourse;
private String sideDish;
private String beverage;
private String dessert;
public Builder mainCourse(String mainCourse) {
this.mainCourse = mainCourse;
return this; // Return Builder for chaining
}
public Builder sideDish(String sideDish) {
this.sideDish = sideDish;
return this;
}
public Builder beverage(String beverage) {
this.beverage = beverage;
return this;
}
public Builder dessert(String dessert) {
this.dessert = dessert;
return this;
}
public Meal build() {
return new Meal(this); // Create Meal object
}
}
// Getters for fields (or other methods)
public String getMainCourse() { return mainCourse; }
public String getSideDish() { return sideDish; }
public String getBeverage() { return beverage; }
public String getDessert() { return dessert; }
@Override
public String toString() {
return "Meal{" +
"mainCourse='" + mainCourse + '\'' +
", sideDish='" + sideDish + '\'' +
", beverage='" + beverage + '\'' +
", dessert='" + dessert + '\'' +
'}';
}
}
// Using Builder
public class Main {
public static void main(String[] args) {
Meal completeMeal = new Meal.Builder()
.mainCourse("Steak")
.sideDish("Potatoes")
.beverage("Water")
.dessert("Cheesecake")
.build();
Meal simpleMeal = new Meal.Builder()
.mainCourse("Chicken")
.build(); // Can be assembled with incomplete set of fields
System.out.println(completeMeal);
System.out.println(simpleMeal);
}
}