0 votes
in Design Patterns by
What problem does Builder Pattern try to solve?

1 Answer

0 votes
by
A builder pattern is a type of creational design pattern that lets to construct complex objects in a step by step manner. The pattern lets to produce different representations of an object using the same construction logic. It helps in creating immutable classes having a large set of attributes. In the Factory and Abstract Factory Design Patterns, we encounter the following issues if the object contains a lot of attributes:

When the arguments are too many, the program will be error-prone while passing from the client to the Factory Class in a specific order. It becomes tedious to maintain the order of arguments when the types are the same.

There might be some optional attributes of the object and yet we would be forced to send all parameters and optional attributes as Null.

When the object creation becomes complex due to heavy attributes, the complexity of this class would become confusing.

The above problems can also be solved by using constructors of required parameters alone. But this causes an issue when there would be new parameters that are added as part of new requirements. This would result in inconsistency. That’s where Builder comes into the picture. This pattern solves the issue of a large number of optional attributes and the inconsistent state by providing means to build an object in a step-by-step way and return the final object utilizing another method.

Builder pattern can be implemented by following the below steps:

Create a static nested class, copy all arguments from the outer class. This nested class would be called the Builder class.

Proper naming convention has to be followed while naming this builder class. For example, if the name of the class is Interviewbit, then the name of the builder would be InterviewbitBuilder.

The builder class should have a public constructor with all required attributes sent as parameters.

The builder class should have methods for setting optional parameters and return the same builder object post setting these values.

The last step is to have a build() method inside the builder class that returns the Object needed by the client. This would require a private constructor in the class that takes the Builder class as the parameter.

Following is the sample example of the builder pattern implementation. We have a User class and we will be building UserBuilder class to build the objects of the User class.

class User

{

   //All final attributes

   private final String firstName; // required

   private final String lastName; // required

   private final int age; // required

   private final String phoneNbr; // optional

   private final String address; // optional

   private final String nationality; //optional

   private User(UserBuilder builder) {

       this.firstName = builder.firstName;

       this.lastName = builder.lastName;

       this.age = builder.age;

       this.phoneNbr = builder.phoneNbr;

       this.address = builder.address;

       this.nationality = builder.nationality;

   }

   //Setters are not provided to make it immutable

   public String getFirstName() {

       return firstName;

   }

   public String getLastName() {

       return lastName;

   }

   public int getAge() {

       return age;

   }

   public String getPhoneNbr() {

       return phoneNbr;

   }

   public String getAddress() {

       return address;

   }

   public String getNationality() {

       return nationality;

   }

   @Override

   public String toString() {

       return "User: "+this.firstName+" "+this.lastName+", "+this.age+", "+this.nationality+", "+this.phoneNbr+", "+this.address;

   }

   public static class UserBuilder

   {

       private final String firstName;

       private final String lastName;

       private int age;

       private String phoneNbr;

       private String address;

       private String nationality;

       public UserBuilder(String firstName, String lastName) {

           this.firstName = firstName;

           this.lastName = lastName;

       }

       public UserBuilder age(int age) {

           this.age = age;

           return this;

       }

       public UserBuilder phoneNbr(String phoneNbr) {

           this.phoneNbr = phoneNbr;

           return this;

       }

       public UserBuilder address(String address) {

           this.address = address;

           return this;

       }

       public UserBuilder nationality(String nationality) {

           this.nationality = nationality;

           return this;

       }

       // method to return the constructed object

       public User build() {

           User user =  new User(this);

           validateUserObject(user);

           return user;

       }

       private void validateUserObject(User user) {

           //Validate of the object does not break anything

       }

   }

}

public class Driver{

   public static void main(String[] args) {

       User firstUser = new User.UserBuilder("Harry", "Potter")

       .age(30)

       .phoneNbr("1234567")

       .address("221B Baker Street - London")

       .build();

    

       System.out.println(firstUser);

    

       User secondUser = new User.UserBuilder("Ron", "Weasley")

       .age(32)

       .phoneNbr("5655")

       //no address

       .build();

    

       System.out.println(secondUser);

    

       User thirdUser = new User.UserBuilder("Hermoine", "Granger").age(20).nationality("English")

       //No age

       //No phone

       //no address

       .build();

    

       System.out.println(thirdUser);

   }

}

The output of the above code would be:

User: Harry Potter, 30, null, 1234567, 221B Baker Street - London

User: Ron Weasley, 32, null, 5655, null

User: Hermoine Granger, 20, English, null, null

Related questions

+1 vote
asked May 5, 2023 in Reinforcement Learning by sharadyadav1986
0 votes
asked Nov 1, 2021 in Artificial Intelligence by DavidAnderson
...