BUILDER PATTERN

In general, the details of object construction, such as instantiating and initializing the components that make up the object, are kept within the object, often as part of its constructor. This type of design closely ties the object construction process with the components that make up the object. This approach is suitable as long as the object under construction is simple and the object construction process is definite and always produces the same representation of the object.

However, this design may not be effective when the object being created is complex and the series of steps constituting the object creation process can be implemented in different ways, thus producing different representations of the object. Because the different implementations of the construction process are all kept within the object, the object can become bulky (construction bloat) and less modular. Subsequently, adding a new implementation or making changes to an existing implementation requires changes to the existing code.

Using the Builder pattern, the process of constructing such an object can be designed more effectively. The Builder pattern suggests moving the construction logic out of the object class to a separate class referred to as a builder class. There can be more than one such builder classes, each with different implementations for the series of steps to construct the object. Each builder implementation results in a different representation of the object.

 

The intent of the Builder Pattern is to separate the construction of a complex object from its representation, so that the same construction process can create different representations. This type of separation reduces the object size. The design turns out to be more modular with each implementation contained in a different builder object. Adding a new implementation (i.e., adding a new builder) becomes easier. The object construction process becomes independent of the components that make up the object. This provides more control over the object construction process.

 

The Builder pattern suggests using a dedicated object referred to as a Director, which is responsible for invoking different builder methods required for the construction of the final object. Different client objects can make use of the Director object to create the required object. Once the object is constructed, the client object can directly request from the builder the fully constructed object. To facilitate this process, a new method getObject () can be declared in the common Builder interface to be implemented by different concrete builders.

Builder

  • Specifies an abstract interface for creating parts of a Product object.

ConcreteBuilder

  • Constructs and assembles parts of the product by implementing the Builder interface.
  • Defines and keeps track of the representation it creates.
  • Provides an interface for retrieving the product.

Director

  • Constructs an object using the Builder interface.

Product

  • Represents the complex object under construction. ConcreteBuilder builds the product’s internal representation and defines the process by which it’s assembled.
  • Includes classes that define the constituent parts, including interfaces for assembling the parts into the final result.

 

Steps for creating builder pattern in another way:

Sometimes there is an object with a long list of properties, and most of these properties are optional. Consider an online form which needs to be filled in order to become a member of a site. You need to fill all the mandatory fields but you can skip the optional fields or sometimes it may look valuable to fill some of the optional fields.

The question is, what sort of constructor should we write for such a class? Well writing a constructor with long list of parameters is not a good choice, this could frustrate the client especially if the important fields are only a few. This could increase the scope of error; the client may provide a value accidentally to a wrong field. Long sequences of identically typed parameters can cause subtle bugs. If the client accidentally reverses two such parameters, the compiler won’t complain, but the program will misbehave at runtime.

Instead of making the desired object directly, the client calls a constructor with all of the required parameters and gets a builder object. Then the client calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the client calls a parameterless build method to generate the object.

  • First of all you need to 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 Cake then builder class should be named as CakeBuilder.
  • The Builder class should have a public constructor with all the required 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.
  • The final step is to provide a build () 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.

Example:

Cake.java

package com.myjavablog.builder;

public class Cake {

private final double sugar; //measured by cup
private final double butters; //measured by cup
private final double milk; //measured by cup
private final int cherry;

//Private constructor to enforce object constructor through builder
private Cake(CakeBuilder builder) {
this.sugar = builder.sugar;
this.butters = builder.butters;
this.milk = builder.milk;
this.cherry = builder.cherry;
}

public static class CakeBuilder
{
private double sugar; //measured by cup
private double butters; //measured by cup
private double milk; //measured by cup
private int cherry;

//Setting object properties
public CakeBuilder sugar ( double cup){
this.sugar = cup;
return this;
}
public CakeBuilder butters ( double cup){
this.butters = cup;
return this;
}
public CakeBuilder milk ( double cup){
this.milk = cup;
return this;
}
public CakeBuilder cherry ( int number){
this.cherry = number;
return this;
}

//Return the object created
public Cake build() {
return new Cake(this);
}
}

@Override
public String toString() {
return "Cake{" +
"sugar=" + sugar +
", butters=" + butters +
", milk=" + milk +
", cherry=" + cherry +
'}';
}
}

Testing builder pattern with TestBuilderPattern.java

package com.myjavablog.builder;

public class TestBuilderPattern {

public static void main(String[] args) {

//Create object using builder pattern
Cake chocolateCake = new Cake.CakeBuilder().sugar(1.5).butters(2).milk(6).cherry(3).build();

//Your choice of Cake is ready
System.out.println(chocolateCake);

}
}

 

Output:

Cake{sugar=1.5, butters=2.0, milk=6.0, cherry=3}

In static class setting property, we can use setter method as another option.

As you can clearly see, now a client only needs to provide the mandatory fields and the fields which are important to him. To create the form object now, we need invoke the CakeBuilder constructor which takes the mandatory fields and then we need to call the set of required methods on it and finally the build method to get the form object.

 

When to use the Builder Pattern:

Use the Builder pattern when-

  • The algorithm for creating a complex object should be independent of the parts that make up the object and how they’re assembled.
  • The construction process must allow different representations for the object that’s constructed.

Builder Pattern in JDK:

  • java.lang.StringBuilder#append() (unsynchronized)
  • java.lang.StringBuffer#append() (synchronized)
  • java.nio.ByteBuffer#put() (also on CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer)
  • javax.swing.GroupLayout.Group#addComponent()
  • All implementations of java.lang.Appendable.

 

Leave a Comment

Bitnami