Monday 8 May 2017

Builder Design Pattern in Java

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

Instead of using numerous constructors, the builder pattern uses another object, a builder that receives each initialization parameter step by step and then returns the resulting constructed object at once.

One solution for multiple problems:

1. The intention of the builder pattern is to find a solution to the telescoping constructor anti-pattern.
The telescoping constructor anti-pattern occurs when the increase of object constructor parameter combination leads to an exponential list of constructors.

2. Too Many arguments to pass from client program to the Factory class that can be error prone because most of the time, the type of arguments are same and from client side it’s hard to maintain the order of the argument.

3. Some of the parameters might be optional but in Factory pattern, we are forced to send all the parameters and optional parameters need to send as NULL or we need to make another constructor.

4. If the object is heavy and its creation is complex, then all that complexity will be part of Factory classes that is confusing.

How to Implement Builder Pattern?

1. We need to create a static nested class and then copy all the arguments from the outer class to the Builder class. It will be better to follow naming convention as StringBuilder class.

2. The Builder class should have a public constructor with all the mandatory attributes as parameters.

3. Builder class should have methods to set the optional parameters and it should return the same Builder object after setting the optional attribute.

4. Finally, there should be a method in the builder class that will return the Object needed by client program. For this we need to have a private constructor in the Class with Builder class as argument.
Builder Design Pattern
Example of Builder Pattern:

class Student {

      /** Mandatory fields. */
      private final String firstName;
      private final String lastName;

      /** optional fields. */
      private final int age;
      private final String phone;

      /**
       * private student constructor to assign the inner class values.
       * @param builder
       */
      private Student(StudentBuilder builder) {
            this.firstName = builder.firstName;
            this.lastName = builder.lastName;
            this.age = builder.age;
            this.phone = builder.phone;
      }

      //Only setters to provide immutability.

      public String getFirstName() {
            return firstName;
      }
      public String getLastName() {
            return lastName;
      }
      public int getAge() {
            return age;
      }
      public String getPhone() {
            return phone;
      }

      @Override
      public String toString() {
            return "Student:: "+this.firstName+": "+this.lastName+": "
                     +this.age+": "+this.phone;
      }

      public static class StudentBuilder {

            private final String firstName;
            private final String lastName;

            private int age;
            private String phone;

            /**
             * Mandatory parameters are passed through constructor.
             * @param firstName
             * @param lastName
             */
            public StudentBuilder(String firstName, String lastName) {
                  this.firstName = firstName;
                  this.lastName = lastName;
            }

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

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

            /**
             * Return the finally constructed student object.
             * @return Student object
             */
            public Student build() {
                  Student user =  new Student(this);
                  return user;
            }
      }
}

public class TestStudent {
      public static void main(String[] args) {
            // With all parameters.
            Student std1 = new Student.StudentBuilder("Rajesh", "dixit")
                                    .age(24).phone("9654900572").build();
            System.out.println(std1);

           
            // With few optional parameters.
            Student std2 = new Student.StudentBuilder("Deeshraj", "Thakur")
                                    .age(22).build();
            System.out.println(std2);

            // No optional parameters.
            Student std3= new Student.StudentBuilder("Deeshraj", "Thakur")
                                   . build();
            System.out.println(std3);
      }
}

Output:
      Student:: Rajesh: dixit: 24: 9654900572
      Student:: Deeshraj: Thakur: 22: null
      Student:: Deeshraj: Thakur: 0: null


Builder Design Pattern Example in JDK
java.lang.StringBuilder#append() (unsynchronized)
java.lang.StringBuffer#append() (synchronized)

No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...