Builder design pattern is one of the most important and simple design pattern in java.
We use it in real life also. For instance, consider assembling a car or making a burger. It is similar to making an object of a class in Object Oriented Programming for example navigation menu of any application.
Let’s understand the builder pattern with our example for burger. So our friends Becky and Sam decide to go for a long drive. On their way they see a burger outlet and decide to stop for a snack. Becky orders for a classic cheese burger but Sam is on a diet and hence goes for a veggie variation of the burger 😛 . Also there are many different people present in the outlet who are ordering different types of burgers.
There they notice that burger making involves different processes, like toasting the bread, creating patty for burger, making sauces and then everything is put together.
In case of programming this is where the Builder pattern comes into picture.
Builder pattern can be defined as, a design pattern that separates the construction of a complex object from its representation.
What is construction and representation of an object?
- Representation: This step consists of how our product looks at the end when it is ready. In this step we combine the already constructed parts.
- For instance first there is a bread, then patty on top it followed by some veggies, then some sauces and at the end finished off with final layer of bread.
- Construction: whereas, this step means how the parts of the products are actually made. This may include multiple steps.
- For example baking a bread, making burger patty, making different sauces, cutting of vegetables etc.
Builder pattern separates these 2 steps so that we can create different type of products using the same set of steps. Thus, it provides flexible solution to object creation problems.
Where to use Builder pattern?
What to solve?
The Builder design pattern solves problems like:
- How can a class (the same construction process) create different representations of a complex object?
- How can a class that includes creating a complex object be simplified?
Creating and assembling the parts of a complex object directly within a class is inflexible. Let's say we have a class with parameterized constructor with some parameters. If we want to create an object of this class, we need to pass all the parameters of the constructor. If we need to create object with different set of parameters we can not do with same constructor.
This makes it impossible to change the representation of the object later without changing the class.
How to solve?
The Builder design pattern describes how to solve such problems:
- A class delegates object creation to a Builder object instead of creating the objects directly.
- Encapsulate creating and assembling the parts of a complex object in a separate Builder object.
A builder class can create different representations of a complex object.
As we can see in the figure below, the construction process of the burger. The same process can be used to create different types of burgers.
Thus we can see the application of the builder pattern in our day to day life. Now, let us learn how to programmatically apply this pattern to our code in the following sections.
How does Builder pattern work?
Let us divide the code in 3 parts to understand how this pattern works. Then we will see the significance of each part.
- Product : This part of the code is the actual object that we are trying to build. For example, in our case it would be 'the burger'.
- Builder : It will contain the general methods needed to build the product.
- Executor : This is the important part which actually calls the builder methods to create the 'Product'. This in our case would be the 'Employee' who prepares the burger for us. He/She will invoke appropriate method from the 'BurgerBuilder'
Let us see in the following section how can we put this together in a code.
Implementation of Builder pattern
Let us now see the implementation of this pattern in Java. We will see each part one by one starting with the "Product", which in our case is the "Burger". This is just a normal entity of which we need to create different instances as per our requirement.
package main.java.creational.builder;
public class Burger {
private String bread;
private String patty;
private String veggies;
private String sauces;
private Boolean withExtraCheese = Boolean.FALSE;
public String getBread() { return bread; }
public void setBread(String bread) { this.bread = bread; }
<......... Getters and setters for these properties>
@Override
public String toString() {
return "Burger [bread=" + bread + ", patty=" + patty + ",
veggies=" + veggies + ", sauces=" + sauces + ",
withExtraCheese=" + withExtraCheese + "]";
}
}
The next part of our pattern is the "Builder" itself. As the name suggests, this is the class contains the methods we need to build the product.
package main.java.creational.builder;
public class BurgerBuilder {
private Burger burger;
public BurgerBuilder () { this.burger = new Burger(); }
public void addBread(String bread) { burger.setBread(bread); }
public void addPatty(String patty ) { burger.setPatty(patty); }
public void addVeggies(String veggies ) { burger.setVeggies(veggies ); }
public void addSauce(String sauce) { burger.setSauces(sauce); }
public void addCheeze() { burger.setWithExtraCheese(Boolean.TRUE); }
public Burger build() { return this.burger; }
}
Now, we come to the last but important part of our code. This is called as the "Executor". Executor calls the builder methods to create the product.
Thus we will have an "Employee" to create the veg burger of us in our example. Let us take a look at how our Employee looks like! 😛
package main.java.creational.builder;
public class Employee {
public static void main(String[] args) {
Burger vegBurger = new BurgerBuilder()
.addBread("Brown Bread")
.addPatty("Veggie")
.addVeggies("Pickles")
.addSauce("All")
.addCheeze().build();
}
}
Advantages
- Allows you to vary a product’s internal representation.
- Encapsulates code for construction and representation.
- Provides control over steps of construction process.
Disadvantages
- Data members of class aren't guaranteed to be initialized.
- Dependency injection may be less supported.
Fast track reading
- Builder design pattern is one of the structural design pattern
- Separates the construction of a complex object from its representation
- Simplifies the creation of complex object
- Different representation of object is possible