Why do we need builders? Lets say we have a class Pizza
Let's say the topping and seasoning are optional. You are a merciless person if you have constructors like these to construct a Pizza.
A builder would've been handy here. The top reasons we should go for a builder are,
~Surya
public Pizza {
private String flour;
private String type;
private String topping;
private String seasoning;
}
Let's say the topping and seasoning are optional. You are a merciless person if you have constructors like these to construct a Pizza.
public Pizza(String flour, String type, String topping, String seasoning) {
}
public Pizza(String flour, String type, String topping) {
}
public Pizza(String flour, String type, String seasoning) {
}
public Pizza(String flour, String type) {
}
I would end up constructing an "Oregono pizza topped with wheat flour with a tomato seasoning". This might be the worst pizza you could ever have.A builder would've been handy here. The top reasons we should go for a builder are,
- Ambiguous class construction. Similar typed fields in Pizza class make its construction ambiguous for the clients.
- If you want to avoid setters and make your objects thread safe especially when there are mandatory and optional fields in your class.
- Too many fields and you don't want to make your constructor look like a cargo train.
public class Pizza {
private final String flour;
private final String type;
private final String topping;
private final String seasoning;
private Pizza(PizzaBuilder builder) {
ValidateNotNull(builder.flour);
ValidateNotNull(builder.type);
this.flour = builder.flour;
this.type = builder.type;
this.topping = builder.topping;
this.seasoning = builder.seasoning;
}
// have getters for fields
pubic static PizzaBuilder getPizzaBuilder() {
return new PizzaBuilder();
}
private class PizzaBuilder {
private String flour;
private String type;
private String topping;
private String seasoning;
public void withFlour(String flour) {
this.flour = flour;
return this;
}
public PizzaBuilder withType(String type) {
this.type = type;
return this;
}
public PizzaBuilder withTopping(String topping) {
this.topping = topping;
return this;
}
public PizzaBuilder withSeasoning(String seasoning) {
this.seasoning = seasoning;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
}
Now the clients can construct a pizza like,Pizza myFavoritePizza = Pizza.getPizzaBuilder().withFlour("Wheat").withType("Cheese").withSeasoning("Oregano").build();
This looks way better than our first approach. Isn't it? No other thread can mess with myFavoritePizza :)~Surya