Reading Time: 5 minutes

Builder Design Pattern Java Real World Example

Builder Design Pattern

The Builder Design Pattern is a classic Gang of Four creational design pattern. Unlike Pattern Design pattern, the Builder Design Pattern tackles the issues with the creation of objects due to complicated constructors.

There are scenarios when a class consists of too many parameters which can get confusing understand mainly when they all have common data types. Mostly a constructor is created by using all the parameters of the class which includes the one which is optional or rarely used.

While creating objects of such class we need to consult the documentation of the class to understand the order of the parameter and need to send null incase of the optional parameter.

Another option is to create multiple constructors with the required parameters. But this approach is not really scalable when many parameters are involved. Builder Design Pattern is also very useful while creating an immutable object.

Builder pattern solves the issue with a large number of optional parameters and inconsistent state by providing a way to build the object step-by-step and provide a method that will actually return the final Object. The process of constructing an object is generic so that it can be used to create different representations of the same object.

Builder Design Pattern uses Method Chaining to implement builder methods.

Method Chaining is used to invoke multiple methods on the same object which occurs as a single statement. Method-chaining is implemented by a series of methods that return the this reference for a class instance.

As return values of methods in a chain is this reference, this implementation allow us to invoke methods in the chain by having the next method invocation on the return value of the previous method in the chain.

This tutorial is a part of Creational Design Pattern Series. Take a look at other Creational Design Patterns:

  1. Singleton Creational Design Pattern Java Explained [6 Code Example]
  2. Factory Design Pattern Java Simplified [Simple Real World Example]
  3. Factory Method Design Pattern Java Simple Detailed Examples
  4. Abstract Factory Design Pattern Java Real World Example
  5. Builder Design Pattern Java Real World Example
  6. Prototype Design Pattern Java Real World Example

 

When to use Builder Design Pattern?

  1. Builder Pattern should be used whenever a complex constructor is involved.
  2. When Object needs to be made in steps.
  3. When we need to create an immutable class.
  4. When we have to create an object which has multiple optional parameters.

Builder Design Pattern Implementation

  1. Create an Outer Class only with arguments. There is no need to create any public constructor and setter/getter methods.
  2. Create a static nested class and then copy all the arguments from the outer class to the Builder class. We should follow the naming convention and if the class name is Student then the builder class should be named as SrudentBuilder.
  3. The Builder class should have a public constructor with all the required/mandatory attributes as parameters.
    Builder class should have methods to set the optional parameters and it should return the same Builder object after setting the optional attribute.
  4. The final step is to provide a build() method in the builder class that will return the Outer class Object needed by the client program. For this, we need to have a private constructor in the Outer Class with Builder class Object as an argument.

Builder Design Pattern Real World Example

Consider a scenario in which a client has a certification website and they want to ask students their personal information. The student is provided with a form that has multiple questions, of which only firstName and lastName are mandatory.

The client wants to store this information in an immutable object. We can save this information by directly calling the constructor, but the form has ample questions and students can choose to answer only some of them.

It is not practical to create a constructor with different combinations. This is a perfect scenario for using the Builder Design Pattern.

Product Class

Student class is our product class and it has a static inner class StudentBuilder.

package com.adevguide.java.designpatterns.builder;

public class Student {

    private String firstName; // mandatory
    private String lastName; // mandatory
    private String age; // optional
    private String gender; // optional
    private boolean isGraduate; // optional
    private boolean hasExperience; // optional
    private String city; // optional
    private String state; // optional
    private boolean isEarning; // optional

    private Student(StudentBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.gender = builder.gender;
        this.isGraduate = builder.isGraduate;
        this.hasExperience = builder.hasExperience;
        this.city = builder.city;
        this.state = builder.state;
        this.isEarning = builder.isEarning;
    }

    @Override
    public String toString() {
        return " firstName=" + firstName + "\n lastName=" + lastName + "\n age=" + age + "\n gender=" + gender
                + "\n isGraduate=" + isGraduate + "\n hasExperience=" + hasExperience + "\n city=" + city + "\n state="
                + state + "\n isEarning=" + isEarning;
    }

    public static class StudentBuilder {

        private String firstName;
        private String lastName;
        private String age;
        private String gender;
        private boolean isGraduate;
        private boolean hasExperience;
        private String city;
        private String state;
        private boolean isEarning;

        public StudentBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public StudentBuilder addAge(String age) {
            this.age = age;
            return this;
        }

        public StudentBuilder addGender(String gender) {
            this.gender = gender;
            return this;
        }

        public StudentBuilder addisGraduate(boolean isGraduate) {
            this.isGraduate = isGraduate;
            return this;
        }

        public StudentBuilder addHasExperience(boolean hasExperience) {
            this.hasExperience = hasExperience;
            return this;
        }

        public StudentBuilder addCity(String city) {
            this.city = city;
            return this;
        }

        public StudentBuilder addState(String state) {
            this.state = state;
            return this;
        }

        public StudentBuilder addIsEarning(boolean isEarning) {
            this.isEarning = isEarning;
            return this;
        }

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

    }

}

The outer class Student has one private constructor Student(StudentBuilder builder) which accepts the builder object and then initializes the class parameters.

The static inner class StudentBuilder has one public constructor which has mandatory parameters as arguments. This is not compulsory to have, we can always create a no-argument constructor and feed mandatory parameters via method as optional parameters.

The static inner class has a separate method for each of the optional parameters which will set the parameter value in the object and return the instance of the object.

Finally, public build() method is required, this will invoke an outer class private constructor, pass it builder class instance and return the outer class instance.

Client Class

package com.adevguide.java.designpatterns.builder;

/**
 * @author PraBhu
 *
 */
public class Client {

    public static void main(String[] args) {

        Student student = new Student.StudentBuilder("Pra", "Bhu") // mandatory parameters
                .addAge("25") // optional
                .addGender("M") // optional
                .addHasExperience(true) // optional
                .build(); // to get back student option

        System.out.println(student);

    }

}

 

Output:

firstName=Pra
lastName=Bhu
age=25
gender=M
isGraduate=false
hasExperience=true
city=null
state=null
isEarning=false

 

Advantages of Builder Pattern Design

  • It provides a clear separation between the construction and representation of an object.
  • immutability is forced to the object once it is created.
  • Object Creation code less error-prone as a user will know what they are passing because of the explicit method call.
  • The builder pattern increases robustness, as the only fully constructed object will be available to the client.

Pitfalls Of Builder Design Pattern

  • The builder pattern is verbose and requires code duplication as Builder needs to copy all fields from Original/Outer Class.

Example Of Builder Design Pattern

  • java.lang.StringBuilder#append()
  • java.nio.ByteBuffer#put() (also in CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer)
  • java.lang.StringBuffer#append()
  • javax.swing.GroupLayout.Group#addComponent()

Builder Design Pattern Source Code

Source code used in this tutorial can be found at GitHub

GitHub Source Code

 

References

https://medium.com/@ajinkyabadve/builder-design-patterns-in-java-1ffb12648850