Builder Design Pattern


Intent

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

Advantage of Builder Design Pattern

The main advantages of Builder Pattern are as follows:
  • It provides clear separation between the construction and representation of an object.
  • It provides better control over construction process.
  • It supports to change the internal representation of objects.

Structure

Participants

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.

Collaborations

  1. The client creates the Director object and configures it with the desired Builder object.
  2. Director notifies the builder whenever a part of the product should be built.
  3. Builder handles requests from the director and adds parts to the product.
  4. The client retrieves the product from the builder. 

Implementation

  • 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 Hero then builder class should be named as 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 client program. For this we need to have a private constructor in the Class with Builder class as argument. 
Let's create Hero class and it's 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 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 :

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.

Real world examples

Comments