Builder Pattern — A Quick Guide

Design Patterns: Builder Pattern

Emre Tanrıverdi
2 min readMay 23, 2021

“Builder Pattern helps us construct complex objects by allowing creation of different representations of that object using same construction code.”

Photo by neonbrand on Unsplash

Builder Pattern is just a simple alternative of telescoping constructors and
many lines of setters.

public class Pizza {   private int slices;
private boolean cheese;
private boolean mushrooms;
public Pizza(int slices) { … }
public Pizza(int slices, boolean cheese) { … }
public Pizza(int slices, boolean cheese, boolean mushrooms) { … }
// implement methods }

So this is what a telescoping constructor look like.
We can extend it even more:

public Pizza(int slices, boolean cheese, boolean mushrooms, boolean pepperoni, boolean onions, boolean studentDiscount…) { … }

Assuming slices is a required parameter and the rest of them is not,
it wouldn’t be wise to create a different constructor for each optional field to satisfy all object combinations.

Simplest way to get rid of this would be to just create a constructor which takes slice parameter and sets rest of the fields upon our needs.

public class Pizza {   private int slices;
private boolean cheese;
private boolean mushrooms;
public Pizza(int slices) { … } }

And the client code would be like:

Pizza pizza = new Pizza(2);pizza.setCheese(true);
pizza.setMushrooms(true);
pizza.setPepperoni(true);

This alternative doesn’t look good either.
The easiest way to save this code is to make a builder class, such as:

public class Pizza {
private int slices;
private boolean cheese;
private boolean mushrooms;
private boolean pepperoni;
private boolean onions;
private boolean studentDiscount;

public Pizza(Builder builder) {
this.slices = builder.slices;
this.cheese = builder.cheese;
this.mushrooms = builder.mushrooms;
this.pepperoni = builder.pepperoni;
this.onions = builder.onions;
this.studentDiscount = builder.studentDiscount;
}

// getters & setters

public static final class Builder {
private int slices;
private boolean cheese;
private boolean mushrooms;
private boolean pepperoni;
private boolean onions;
private boolean studentDiscount;

private Builder() {}

public static Builder initialize(int slices) {
return new Builder().withSlices(slices);
}

public Builder withSlices(int slices) {
this.slices = slices;
return this;
}

public Builder withCheese() {
this.cheese = true;
return this;
}

public Builder withMushrooms() {
this.mushrooms = true;
return this;
}

public Builder withPepperoni() {
this.pepperoni = true;
return this;
}

public Builder withOnions() {
this.onions = true;
return this;
}

public Builder withStudentDiscount() {
this.studentDiscount = true;
return this;
}

public Pizza build() {
return new Pizza(this);
}
}
}

Since slices is a required field, Builder’s private constructor is hidden and has a simple factory method that only permits to initialize with slices.

Up until build() method is called, Builder returns a Builder type,
build()
method transforms Pizza.Builder to an actual Pizza object.

And the client code would be like:

Pizza pizza = Pizza.Builder
.initialize(2)
.withCheese()
.withMushrooms()
.withStudentDiscount()
.build();

Voila!

Thank you for reading and being a part of my journey!

Reference(s)

  • Dive into Design Patterns. by Alexander Shvets, Released 2019.

--

--