The Builder Design Pattern provides one of the best ways to create an object. So it comes under creational pattern. The builder pattern is an object creation software design pattern. Instead of using numerous constructors in case of abstract factory pattern and factory method pattern, 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.

The definition in original Gang of Four book is given below

Allows for object level access control by acting as a pass through entity or a placeholder object.

Class Diagram

Builder Design Pattern in Java

What problem a Builder design pattern solves

Take an example, a class with a list of constructors where each addition adds a new option parameter:

Cake(double sugar) { ... }
Cake(double sugar, double butter) { ... }
Cake(double sugar, double butter, double flour) { ... }
Cake(double sugar, double butter, double flour, double bakingpowder) { ... }
Cake(double sugar, double butter, double flour, double bakingpowder, int eggs) { ... }
Cake(double sugar, double butter, double flour, double bakingpowder, int eggs, int vanila) { ... }
Cake(double sugar, double butter, double flour, double bakingpowder, int eggs, int vanila, double milk) { ... }
Cake(double sugar, double butter, double flour, double bakingpowder, int eggs, int vanila, double milk, int cherry) { ... }

This is called the Telescoping Constructor Pattern. The problem with this pattern is that once constructors are 4 or 5 parameters long it becomes difficult to remember the required order of the parameters as well as what particular constructor we might want in a given situation.

One alternative we have to the Telescoping Constructor Pattern is the JavaBean Pattern where we call a constructor with the mandatory parameters and then call any optional setters after:

Cake cake = new Cake(250.0);
cake.setButter(100.0);
cake.setFlour(500.0);
cake.setBakingpowder(50.0);

The problem here is that because the object is created over several calls it may be in an inconsistent state partway through its construction. This also requires a lot of extra effort to ensure thread safety.

So the better alternative is to use the Builder Pattern.

The builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters. For example imagine a DOM. We have to create plenty of nodes and attributes to get our final object. A factory is used when the factory can easily create the entire object within one method call.

Advantages

1) more maintainable if number of fields required to create object is more than 4 or 5.
2) less error-prone as user will know what they are passing because of explicit method call.
3) more robust as only fully constructed object will be available to the client.

Disadvantages

verbose and code duplication as Builder pattern needs to copy all fields from original class.

Implementation

To make a Cake we will follow several steps

a. mix ingredients
b. bake
c. frost

In the below example, we will create an abstract class CakeBuilder to define these three steps. Any class which extends CakeBuilder will follow the same steps to make a cake. Then we will use CakeDirector class to force the order of these three steps, i.e., we have to first mix ingredients, then bake and at last we have to frost the made cake. The CakeClient orders the cake of two types, one is Veg Cake and another one is Non-Veg Cake. Even though cakes are of different types but they are made in the same way. The making process allows different representation for the object that is created.

package com.roytuts.designpattern.builderpattern;

public abstract class CakeBuilder {

  protected Cake cake;
  protected Ingredients ingredients;
  protected Bake bake;
  protected Frost frost;

  public abstract Cake createCake();

  public abstract Ingredients mixIngredients();

  public abstract Bake bakeMixedIngredients();

  public abstract Frost frostCake();
}
package com.roytuts.designpattern.builderpattern;

public interface Ingredients {
  public String getIngredients();
}
package com.roytuts.designpattern.builderpattern;

public interface Bake {
  public String getBaked();
}
package com.roytuts.designpattern.builderpattern;

public interface Frost {
  public String getFrost();
}
package com.roytuts.designpattern.builderpattern;

public abstract class Cake {

  protected Ingredients ingredients;
  protected Bake bake;
  protected Frost frost;

  public Ingredients getIngredients() {
    return ingredients;
  }

  public void setIngredients(Ingredients ingredients) {
    this.ingredients = ingredients;
  }

  public Bake getBake() {
    return bake;
  }

  public void setBake(Bake bake) {
    this.bake = bake;
  }

  public Frost getFrost() {
    return frost;
  }

  public void setFrost(Frost frost) {
    this.frost = frost;
  }

  public abstract String getCake();
}
package com.roytuts.designpattern.builderpattern;

public class VegCake extends Cake {

  @Override
  public String getCake() {
    return "Make a Veg Cake";
  }

}
package com.roytuts.designpattern.builderpattern;

public class VegCakeIngredients implements Ingredients {

  @Override
  public String getIngredients() {
    return "Get ingredients for Veg Cake";
  }

}
package com.roytuts.designpattern.builderpattern;

public class VegCakeBake implements Bake {

  @Override
  public String getBaked() {
    return "Bake the Veg Cake at 350 degree centigrade";
  }

}
package com.roytuts.designpattern.builderpattern;

public class VegCakeFrost implements Frost {

  @Override
  public String getFrost() {
    return "Cool and frost the Veg Cake as desired";
  }

}
package com.roytuts.designpattern.builderpattern;

public class VegCakeBuilder extends CakeBuilder {

  @Override
  public Cake createCake() {
    return new VegCake();
  }

  @Override
  public Ingredients mixIngredients() {
    return new VegCakeIngredients();
  }

  @Override
  public Bake bakeMixedIngredients() {
    return new VegCakeBake();
  }

  @Override
  public Frost frostCake() {
    return new VegCakeFrost();
  }

}
package com.roytuts.designpattern.builderpattern;

public class NonVegCake extends Cake {

  @Override
  public String getCake() {
    return "Make a Non-Veg Cake";
  }

}
package com.roytuts.designpattern.builderpattern;

public class NonVegCakeIngredients implements Ingredients {

  @Override
  public String getIngredients() {
    return "Get ingredients for Non-Veg Cake";
  }

}
package com.roytuts.designpattern.builderpattern;

public class NonVegCakeBake implements Bake {

  @Override
  public String getBaked() {
    return "Bake the Non-Veg Cake at 400 degree centigrade";
  }

}
package com.roytuts.designpattern.builderpattern;

public class NonVegCakeFrost implements Frost {

  @Override
  public String getFrost() {
    return "Cool and frost the Non-Veg Cake as desired";
  }

}
package com.roytuts.designpattern.builderpattern;

public class NonVegCakeBuilder extends CakeBuilder {

  @Override
  public Cake createCake() {
    return new NonVegCake();
  }

  @Override
  public Ingredients mixIngredients() {
    return new NonVegCakeIngredients();
  }

  @Override
  public Bake bakeMixedIngredients() {
    return new NonVegCakeBake();
  }

  @Override
  public Frost frostCake() {
    return new NonVegCakeFrost();
  }

}
package com.roytuts.designpattern.builderpattern;

public class CakeDirector {

  public Cake makeCake(CakeBuilder cakeBuilder) {
    Cake cake = cakeBuilder.createCake();
    System.out.println(cake.getCake());
    cake.setIngredients(cakeBuilder.mixIngredients());
    System.out.println(cake.getIngredients().getIngredients());
    cake.setBake(cakeBuilder.bakeMixedIngredients());
    System.out.println(cake.getBake().getBaked());
    cake.setFrost(cakeBuilder.frostCake());
    System.out.println(cake.getFrost().getFrost());
    return cake;
  }

}
package com.roytuts.designpattern.builderpattern;

public class CakeClient {

  /**
   * @param args
   */
  public static void main(String[] args) {
    CakeDirector cakeDirector = new CakeDirector();

    //make a veg cake
    VegCakeBuilder vegCakeBuilder = new VegCakeBuilder();
    cakeDirector.makeCake(vegCakeBuilder);
    System.out.println();

    //make a non-veg cake
    NonVegCakeBuilder nonVegCakeBuilder = new NonVegCakeBuilder();
    cakeDirector.makeCake(nonVegCakeBuilder);
  }

}

Run the class CakeClient and see the below output in the console

Make a Veg Cake
Get ingredients for Veg Cake
Bake the Veg Cake at 350 degree centigrade
Cool and frost the Veg Cake as desired

Make a Non-Veg Cake
Get ingredients for Non-Veg Cake
Bake the Non-Veg Cake at 400 degree centigrade
Cool and frost the Non-Veg Cake as desired

That’s all. Thank you for your reading.

Tags:

I am a professional Web developer, Enterprise Application developer, Software Engineer and Blogger. Connect me on Roy Tutorials | TwitterFacebook Google PlusLinkedin | Reddit | Email Me

0 thoughts on “Builder Design Pattern in Java

  1. Great and informative article on builder design pattern in java. Its good to know the concept of this builder design patter with good example that you have shared. As a java beginner it is very helpful to go through this precise and understanding article, thanks a lot!

Leave a Reply

Your email address will not be published. Required fields are marked *