We will discuss Builder design pattern.
Key topics we are going to discuss are :
– Which category Builder Design Pattern falls in ?
– What problem builder Pattern is solving or when to use Builder pattern?
– Builder Pattern
– Builder Pattern Example
– Advantages of Builder Pattern
– Disadvantages of Builder Pattern
Which category Builder Design Pattern falls in ?
Builder pattern falls under Creational design patterns category, as it deals with the creation of object(s).Please note that Builder design pattern that I am going to describe here is not GOF design pattern but the one suggested by Joshua block in
Effective Java, as I personally see this pattern used for more often or more practical than the one suggested by GOF.
What problem builder Pattern is solving or when to use Builder pattern?
In nutshell, you should use Builder design pattern when :
– You have a class, which has some mandatory fields and some optional fields, which in other words means that your object can be constructed in various ways as per requirements. Although you are free to use it with a class with all mandatory fields as well when number of fields are too many(usually more than four is a good candidate).
– You want objects of your class to be immutable, which means once objects are instantiated there state can not be changed after that.
Now lets discuss these points in more detail.
You have a class with some mandatory and some optional fields :
What is the problem with having optional fields.
Let us say you have below Student class with mandatory and optional fields and have a constructor with all the fields.
package com.blogspot.oraclejavacertified;
public class Student {
//mandatory fields
private final String id;
private String firstName;
private String lastName; //optional fields
private String age;
private String houseNumber;
private String streetNumber;
public Student(String id, String firstName, String lastName, String age, String houseNumber, String streetNumber) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.houseNumber = houseNumber;
this.streetNumber = streetNumber;
}
public String getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getAge() {
return age;
}
public String getHouseNumber() {
return houseNumber;
}
public String getStreetNumber() {
return streetNumber;
}
}
Now, say the client of this code might want to create instance of Student with
– Only Mandatory fields
– All the Mandatory as well as optional fields
– Mandatory fields and one or more of the optional fields
Then the constructors for above scenarios will look like as below :
//Only Mandatory fields Student student2 = new Student("201", "firstName2", "surName2", null, null, null);
//All the Mandatory as well as optional fields Student student1 = new Student("101", "firstName1", "surName1", "16", "11", "2");
//Mandatory fields and one or more optional fields Student student3 = new Student("301", "firstName3", "surName3", "20", null, null);
Student student4 = new Student("301", "firstName4", "surName4", "20", "22", null);
Now, what is the problem with the above constructors?
Actually, there are multiple problems, like
– Client code has to unnecessarily pass null for all optional fields.
– Code readability is not good. As the number of parameters grow, it becomes difficult and error prone for client code to understand what needs to be passed at which position and later to read for the person who is going to maintain the code.
– When adjacent parameters are of same data type, you might accidently exchange their values which will go unnoticed at compile time but create some severe bug at run time. For example, developer can accidently interchange values for age and houseNumber.
So What can you do to solve these problems ?
Probably we can have look at the Telescoping constructor pattern.
In Telescoping constructor pattern, we create multiple constructor overloads starting with one with all mandatory fields and then with one optional field and then with two optional fields and so on until we have constructor with all fields.Each constructor calls another constructor with one more optional field and passes the default value for the optional field(can be null or any other default you want to set) until the last constructor with all optional fields is called.
package com.blogspot.oraclejavacertified;
public class Student {
//Mandatory fields
private String id;
private String firstName;
private String lastName;
//Optional fields
private String age;
private String houseNumber;
private String streetNumber;
public Student(String id, String firstName, String lastName) {
this(id, firstName, lastName, "0");
}
public Student(String id, String firstName, String lastName, String age) {
this(id, firstName, lastName, age, "0");
}
public Student(String id, String firstName, String lastName, String age, String houseNumber) {
this(id, firstName, lastName, age, houseNumber, "0");
}
public Student(String id, String firstName, String lastName, String age, String houseNumber, String streetNumber) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.houseNumber = houseNumber;
this.streetNumber = streetNumber;
}
}
Now let us see which problems telescoping constructor solved :
– Client code no longer has to pass null for all the optional fields as well.
– From client code perspective, readability is better.
But telescoping constructors comes with its own problems:
– What if more optional fields are added in Student class in future, then for each new field another constructor needs to be introduced.
– Still you need to carefully see all overloads of the constructor and choose the one which suits your requirement.
– Still if you have say age and streetNumber but houseNumber is not available, then you need to instantiate Student class like below, so still client need to pass in null value for optional field.
Student student = new Student("101", "firstName", "lastName", "35", null, "3");
– And still there is possibility of getting exchange of values of same data type, when the number of optional fields are too many.
We will see how builder pattern solves these problems later but for now let us discuss the other aspect which makes a case for using builder pattern.
You want objects of your class to be immutable :
If you don’t want state of your object to get changed once it has been created(and of course it has lots of fields), you can use build pattern, as builder pattern makes sure your object is immutable once it is created.
Advantages of Immutable classes :
– They are more reliable as it is known that their state is not going to change after creation.
– They are inherently thread safe and don’t need any synchronization.
– They make great candidates to be used as a key of a HashMap or to be put in a HashSet.
Now let us see implementation of Builder pattern by taking example of our Student class.
Builder pattern
– In builder pattern , you leave the responsibility of creating object or instantiating your class to Builder which is another class which has exactly same number of fields as your class whose objects builder is going to build.
– As your builder class is going to be used only for creating objects of your class and is not going to be used elsewhere, it is defined as static nested class within your class.
– You provide a builder’s constructor with only mandatory fields and then you provide methods(mutators) in builder to set the remaining optional fields. You can chain these methods as each of these method again returns Builder. Note that till now we are talking only about using builder constructor and using methods to set other optional fields and all these are still part of Builder object and we have not yet created actual Student object, so we are not concerned about immutability yet.
So in terms of code, we are here :
Student.StudentBuilder studentBuilder2 = ("2", "Sachin", "Tendulkar").withAge("47");
Now all we need to do is call build() method of our builder on the created builder instance like below :
studentBuilder2.build()
0 comments:
Post a Comment