Builder Pattern in Java
Design patterns are very important in the world of software development, as they represent well proven and tested solutions for some specific problems and tasks. Builder pattern is one of the most popular and used design patterns in Java. It is used to create instances of very complex objects, for which the usage of constructors would result in very messy and difficult to maintain code.
The problem
For this example we use a class named Person. This class has 2 fields and a constructor for both fields.
public class Person { private String firstName; private String lastName; public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } // Getters and setters }
For this example, the usage is very simple:
Person person = new Person("John", "Doe");
Problems occur when our product gets a new feature which requires you to add more fields to the same class.
Now the Person class will look like this:
public class Person { private String firstName; private String lastName; private String nickname; private int age; private double height; // other fields hidden for readability }
Then you will have parts of code where you only need the first and last name, but somewhere you need the whole object, and somewhere else you will need some other fields.
There are only two ways to solve this problem using conventional methods: create multiple constructors for the same object or have one big constructor and pass null values for the fields you don’t need.
If you decide to create multiple constructors, eventually you will end up having 15 constructors for the same object. This becomes an ideal environment for creating bugs when some changes happen, as you will have to make the same changes for every constructor.
On the other hand, if you decide to go with passing null values to the constructor, as such:
Person person = new Person("John", "Doe", null, 0, 0, 0, BodyType.FIT, null, null);
Not only does this look very unaesthetic, but it’s a recipe for NullPointerExceptions, as you may want to do some calculations in the constructor (e.g. length of nickname).
The solution
When implementing the Builder Pattern, the constructor should be private so the object can only be created from the builder, also there should be no setter methods on the class itself, but this is not a strict rule.
First, we create a nested static class Builder inside the Person class. This class will have the same fields as the original class.
The next step is to create setter methods for each field in the Builder class, but instead of returning void, these setter methods will return the instance of the Builder object.
The last part is the implementation of the build() method, which takes all the fields from the Builder class and uses them as parameters for the construction of the Person object.
public static class Builder { private String firstName; private String lastName; private String nickname; // other fields hidden for readability public Builder setFirstName(String firstName) { this.firstName = firstName; return this; } // other setter methods hidden for readability public Person build() { return new Person(firstName, lastName, nickname, age, height, weight, bodyType, gender, phoneNumber); } }
Now the initialization of objects would be done like this:
Person person1 = new Person.Builder() .setFirstName("John") .setLastName("Doe") .setAge(20) .build(); Person person2 = new Person.Builder() .setFirstName("John") .setLastName("Doe") .setNickname("Johnny") .setAge(20) .setGender(Gender.MALE) .setBodyType(BodyType.FIT) .build();
Not only is the Builder Pattern the easier solution, but it also makes your code readable, more stable and easier to maintain.
“Builder Pattern in Java” Tech Bite was brought to you by Asmir Ljumić, Software Developer at Atlantbh.
Tech Bites are tips, tricks, snippets or explanations about various programming technologies and paradigms, which can help engineers with their everyday job.