Builder Design Pattern

In this post, we will learn how to implement the Builder Design Pattern in Java with step by step example.
Builder Design Pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.

Explanation

This pattern was introduced to solve some of the problems with Factory and Abstract Factory design patterns when the Object contains a lot of attributes. There are three major issues with Factory and Abstract Factory design patterns when the Object contains a lot of attributes.

  1. Too Many arguments to pass from client program to the Factory class that can be error-prone because most of the time, the type of arguments are the same and from client-side it’s hard to maintain the order of the argument.

  2. Some of the parameters might be optional but in the Factory pattern, we are forced to send all the parameters and optional parameters need to send as NULL.

  3. If the object is heavy and its creation is complex, then all that complexity will be part of Factory classes that is confusing.

Builder pattern solves the issue with a large number of optional parameters and inconsistent state by providing a way to build the object step-by-step and provide a method that will actually return the final Object.

Class Diagram

Let's understand the above components of the builder pattern:

1. Builder
  • specifies an abstract interface for creating parts of a Product object.

2. 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.

3. Director

  • constructs an object using the Builder interface.

4. 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.

Builder Design Pattern Implementation

Here are the Step or Rules to design Builder Pattern:
  • 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. For example, if the class name is Hero then the builder class should be named HeroBuilder.
  • 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 the client program. For this, we need to have a private constructor in the Class with Builder class as an argument.

Let's create a Hero class and its constructor passing more parameters:

public final class Hero {
    private final Profession profession;
    private final String name;
    private final HairType hairType;
    private final HairColor hairColor;
    private final Armor armor;
    private final Weapon weapon;

    private Hero(Builder builder) {
        this.profession = builder.profession;
        this.name = builder.name;
        this.hairColor = builder.hairColor;
        this.hairType = builder.hairType;
        this.weapon = builder.weapon;
        this.armor = builder.armor;
    }
}

And then we have the Builder, public static class:

 public static class Builder {
     private final Profession profession;
     private final String name;
     private HairType hairType;
     private HairColor hairColor;
     private Armor armor;
     private Weapon weapon;

     public Builder(Profession profession, String name) {
         if (profession == null || name == null) {
             throw new IllegalArgumentException("profession and name can not be null");
         }
         this.profession = profession;
         this.name = name;
     }

     public Builder withHairType(HairType hairType) {
         this.hairType = hairType;
         return this;
     }

     public Builder withHairColor(HairColor hairColor) {
         this.hairColor = hairColor;
         return this;
     }

     public Builder withArmor(Armor armor) {
         this.armor = armor;
         return this;
     }

     public Builder withWeapon(Weapon weapon) {
         this.weapon = weapon;
         return this;
     }

     public Hero build() {
         return new Hero(this);
     }
 }

Here is a test program showing how to use the Builder class to get the object:

Hero mage = new Hero.Builder(Profession.MAGE, "Riobard").
withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build();

View source code of Builder Design Pattern on my GitHub repository: https://github.com/RameshMF/gof-java-design-patterns

Applicability

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.