Builder pattern is an alternative way to construct complex objects and should be used only when the increase of object constructor parameter combination leads to an exponential list of constructors. 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.
By definition
The builder pattern separates the construction of a complex object from its representation. By doing so the same construction process can create different representations.
Where we use it ?
We use the builder design pattern when we want to achieve immutability in a class with a large set of attributes. The String
class in java is inmutable and is designed so for the sake of efficiency and security. This is also the reason why immutable classes are preferred in general.
Let us explain it with an abstract example. Let us assume we have the class StreetMap
, which identify a route from an origin to a destination. The StreetMap
object has the following 4 attributes i.e. origin
, destination
, landColor
andtrafficColor
.
Normally, if you want to make a immutable StreetMap
class, then you should pass all five information as parameters to the constructor. It will look like this:
public StreetMap (Point origin,Point destination,Color landColor,Color trafficColor){
this.origin = origin;
this.destination = destination
this.landColor = landColor;
this.trafficColor = trafficColor;
}
So far so good. Now what if only origin
and destination
are mandatory and the rest of fields are optional. Houston we have a problem !! We need more constructors.
public StreetMap (Point origin,Point destination, Color landColor){ ...}
public StreetMap (Point origin,Point destination){ ...}
And what about if we introduce a new attribute ?. We have again to create a new constructor. Here, builder pattern will help you to consume additional attributes while retaining the immutability of StreetMap
class.
A complete example
Below is the coded solution of problem we discussed above. This uses a additional inner class Builder
which helps us in building the desired StreetMap
object with all mandatory attributes and combination of optional attributes, without loosing the immutability.
public class StreetMap {
private final Point origin;
private final Point destination;
private final Color landColor;
private final Color trafficColor;
public static class Builder {
// Required parameters
private final Point origin;
private final Point destination;
// Optional parameters - initialize with default values
private Color landColor = new Color(30, 30, 30);
private Color trafficColor = Color.GREEN;
public Builder(Point origin, Point destination) {
this.origin = origin;
this.destination = destination;
}
public Builder landColor(Color color) {
landColor = color;
return this;
}
public Builder trafficColor(Color color) {
trafficColor = color;
return this;
}
public StreetMap build() {
return new StreetMap(this);
}
}
private StreetMap(Builder builder) {
// Required parameters
origin = builder.origin;
destination = builder.destination;
// Optional parameters
landColor = builder.landColor;
trafficColor = builder.trafficColor;
}
public static void main(String args[]) {
StreetMap map = new StreetMap.Builder(new Point(50, 50), new Point(100, 100)).landColor(Color.GRAY).trafficColor(Color.BLUE.brighter()).build();
}
}
Please note that the StreetMap
object does not have any setter method, so its state can not be changed once it has been built. This provides the desired immutability.
Existing implementations in JDK
All implementations of java.lang.Appendable are infact good example of use of Builder pattern in java. e.g.
java.lang.StringBuilder#append() [Unsynchronized class]
java.lang.StringBuffer#append() [Synchronized class]
java.nio.ByteBuffer#put() (also on CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer)
Another use can be found in javax.swing.GroupLayout.Group#addComponent().
Advantages
- Design flexibility
- Much more readable code.
- parameters to the constructor are reduced and thus there is no need to pass in null for optional parameters to the constructor.
- Object is always instantiated in a complete state rather than sitting in an incomplete state until the developer calls (if ever calls) the appropriate “setter” method to set additional fields.
- Easy to build immutable objects without much complex logic in object building process.
Disadvantages
- Requires creating a separate
Builder
for each different type of Product. - Although the builder pattern reduce some line of code buy eliminating the need of setter methods, still it double up total lines by introducing the
Builder
object.
This is a totally educational post.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.