Sunday, 22 May 2011

Using the Builder Pattern to Construct Thread-Safe Objects

A couple of days ago my blog described the benefits of creating immutable POJOs in order to make your programs more thread-safe. Today’s blog builds on that idea, by demonstrating the use of the Builder pattern to construct your POJO’s. It’s strange that I haven’t discussed this before as it’s one of my favourites. You can find it in more detail in Joshua Bloch’s Effective Java Second Edition - page 14.

The idea here is make make object construction as flexible as possible, whilst hiding how the object is constructed by using a nested Builder class. The Builder splits the construction in two using a constructor for mandatory attributes and setter methods for optional ones. In the sample below, I’m constructing a FoodNutrition class with mandatory attributes of id and name, and optional attributes of: fat, calories, servingSize and description. Code that employes the Builder does away with the need for public telescoping constructors and becomes a lot more robust. This is because adding an extra attribute to your class, say for example: protein, has little or no impact on your client code.

This is the code that implements the Builder pattern in the FoodNutrition class.

public class FoodNutrition {

 
private final int id;
 
private final String name;
 
private final int calories;
 
private final int servingSize;
 
private final int fat;
 
private final String description;

 
/** Private constructor to build the object. */
 
private FoodNutrition(int id, String name, int calories, int servingSize, int fat,
      String description
) {
   
this.id = id;
   
this.name = name;
   
this.calories = calories;
   
this.servingSize = servingSize;
   
this.fat = fat;
   
this.description = description;
 
}

 
public int getId() {
   
return id;
 
}

 
public String getName() {
   
return name;
 
}

 
public int getCalories() {
   
return calories;
 
}

 
public int getServingSize() {
   
return servingSize;
 
}

 
public int getFat() {
   
return fat;
 
}

 
public String getDescription() {
   
return description;
 
}

 
/**
   * An internal builder class that constructs our required object
   */
 
public static class Builder {

   
private final int id;
   
private final String name;
   
private int calories;
   
private int servingSize;
   
private int fat;
   
private String description;

   
/**
     * Put the mandatory parameters into the Builder class's constructor
     */
   
public Builder(int id, String name) {
     
this.id = id;
     
this.name = name;
   
}

   
/**
     * Set the calories
     */
   
public Builder calories(int calories) {
     
this.calories = calories;
     
return this;
   
}

   
/**
     * Set the serving size
     */
   
public Builder servingSize(int servingSize) {
     
this.servingSize = servingSize;
     
return this;
   
}

   
/**
     * Set the fat quantity
     */
   
public Builder fat(int fat) {
     
this.fat = fat;
     
return this;
   
}

   
/**
     * Set the description
     */
   
public Builder description(String description) {
     
this.description = description;
     
return this;
   
}

   
public FoodNutrition build() {
     
return new FoodNutrition(id, name, calories, servingSize, fat, description);
   
}
  }
}

You can use this pattern to build objects in the following way:

    // Use of the Builder Pattern
   
FoodNutrition objectBuilder = new FoodNutrition.Builder(1, "Yogurt").calories(23)
       
.description("Made from milk, but often contains added sugar").fat(23).build();
   
   
// Use the new object
   
objectBuilder.toString();

    objectBuilder =
new FoodNutrition.Builder(2, "Bacon").calories(233).fat(235)
       
.servingSize(3).build();
   
   
// Use this object
   
objectBuilder.toString();

Summarising: the pros of using this method are that the final object is immutable, construction is flexible, and can be built in any way. It does have at least one con, which is your client construction code may end up looking like a 'train wreck'.

No comments: