DEV Community

Erwan Le Tutour
Erwan Le Tutour

Posted on

Builder design pattern — java

design-pattern

Definition of Builder Pattern

The builder pattern is a design pattern that allows for the step-by-step creation of complex objects using the correct sequence of actions. The construction is controlled by a director object that only needs to know the type of object it is to create.

Where to use the builder pattern?

When you have a simple object, this pattern is not very useful, but when you begin to have a more complex object and want to have a clear code you can use it without hesitation

For example :

package main.builder;
public class Human {
String name;
String lastName;
int age;
public Human(String name, String lastName, int age) {
this.name = name;
this.lastName = lastName;
this.age = age;
}
}
view raw Human.java hosted with ❤ by GitHub

A constructor with a limited number of parameters won’t be something that will make your code unreadable.
But what if now you have something like this :
package main.builder;
import java.util.Date;
public class Human {
String name;
String lastName;
int age;
String height;
String weight;
String eyesColor;
String hairColor;
String birthPlace;
Date birthDate;
int nomberOfSibling;
boolean married;
public Human(String name, String lastName, int age, String height, String weight, String eyesColor, String hairColor, String birthPlace, Date birthDate, int nomberOfSibling, boolean married) {
this.name = name;
this.lastName = lastName;
this.age = age;
this.height = height;
this.weight = weight;
this.eyesColor = eyesColor;
this.hairColor = hairColor;
this.birthPlace = birthPlace;
this.birthDate = birthDate;
this.nomberOfSibling = nomberOfSibling;
this.married = married;
}
}

The number of parameters to pass to the constructor will make the line of code unreadable.
Yes, you can still use the setter to change the value of a property after you have initialized your object. But what if all your fields are final because you want to render them immutable? (What they will be in the rest of this article) Or what if some fields are mandatory and others don’t?

Implementation of the builder pattern

package main.builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.Date;
@Getter
public class Human {
private final String name;
private final String lastName;
private final int age;
private final String height;
private final String weight;
private final String eyesColor;
private final String hairColor;
private final String birthPlace;
private final Date birthDate;
private final int numberOfSibling;
private final boolean married;
private Human(HumanBuilder builder){
this.name = builder.name;
this.lastName = builder.lastName;
this.age = builder.age;
this.height = builder.height;
this.weight = builder.weight;
this.eyesColor = builder.eyesColor;
this.hairColor = builder.hairColor;
this.birthPlace = builder.birthPlace;
this.birthDate = builder.birthDate;
this.numberOfSibling = builder.numberOfSibling;
this.married = builder.married;
}
@NoArgsConstructor
public static class HumanBuilder{
private String name;
private String lastName;
private int age;
private String height;
private String weight;
private String eyesColor;
private String hairColor;
private String birthPlace;
private Date birthDate;
private int numberOfSibling;
private boolean married;
public HumanBuilder withName(String name){
this.name = name;
return this;
}
public HumanBuilder withLastName(String lastName){
this.lastName = lastName;
return this;
}
public HumanBuilder withAge(int age){
this.age = age;
return this;
}
public HumanBuilder withHeight(String height){
this.height = height;
return this;
}
public HumanBuilder withWeight(String weight){
this.weight = weight;
return this;
}
public HumanBuilder withEyesColor(String eyesColor){
this.eyesColor = eyesColor;
return this;
}
public HumanBuilder withHairColor(String hairColor){
this.hairColor = hairColor;
return this;
}
public HumanBuilder withBirthPlace(String birthPlace){
this.birthPlace = birthPlace;
return this;
}
public HumanBuilder withBirthDate(Date birthDate){
this.birthDate = birthDate;
return this;
}
public HumanBuilder withNumberOfSibling(int numberOfSibling){
this.numberOfSibling = numberOfSibling;
return this;
}
public HumanBuilder isMarried(boolean married){
this.married = married;
return this;
}
public Human build(){
Human human = new Human(this);
return human;
}
}
@Override
public String toString() {
return "Human{" +
"name='" + name + '\'' +
", lastName='" + lastName + '\'' +
", age=" + age +
", height='" + height + '\'' +
", weight='" + weight + '\'' +
", eyesColor='" + eyesColor + '\'' +
", hairColor='" + hairColor + '\'' +
", birthPlace='" + birthPlace + '\'' +
", birthDate=" + birthDate +
", numberOfSibling=" + numberOfSibling +
", married=" + married +
'}';
}
}

I have used Lombok to not code the getter and the default constructor because the builder pattern doubles the number of lines of code.
So this is the implementation of my HumanBuilder, now how can I declare a Human with it? Nothing difficult you will see (or should I say read ?).
package main.builder;
public class HumanMain {
public static void main(String[] args) {
Human erwan = new Human.HumanBuilder()
.withName("Erwan")
.withAge(30)
.withBirthPlace("Saint Cyr l'Ecole")
.isMarried(true)
.withNumberOfSibling(2)
.build();
System.out.println(erwan.toString());
}
}
view raw HumanMain.java hosted with ❤ by GitHub

That will give this output
Human{
  name='Erwan', 
  lastName='null', 
  age=30, 
  height='null', 
  weight='null', 
  eyesColor='null', 
  hairColor='null', 
  birthPlace='Saint Cyr l'Ecole', 
  birthDate=null, 
  numberOfSibling=2, 
  married=true
}
Enter fullscreen mode Exit fullscreen mode

As you can see, I can choose the number of parameters to initialize and their order.

Neon image

Serverless Postgres in 300ms (❗️)

10 free databases with autoscaling, scale-to-zero, and read replicas. Start building without infrastructure headaches. No credit card needed.

Try for Free →

Top comments (0)

Jetbrains image

Is Your CI/CD Server a Prime Target for Attack?

57% of organizations have suffered from a security incident related to DevOps toolchain exposures. It makes sense—CI/CD servers have access to source code, a highly valuable asset. Is yours secure? Check out nine practical tips to protect your CI/CD.

Learn more

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay