Java Design Pattern: Builder Pattern

A valid alternative to contructors



Today we are going to talk about a creational pattern that in many situations can represent a useful alternative to the construction of the objects using the constructors: the Builder Pattern.

The need to introduce alternative mechanisms to those provided by Java for the creation of objects is originated from the fact that sometimes the structures are very complex and it is not always trivial to set up a well-formed constructor. Think of the cases in which the number of attributes is very high or the cases in which there are attributes that may not even be valued. The probability of making a mistake by writing the constructor by hand is very high.

The goal is to separate the creation of the object from its representation. In this way, the algorithm for creating the object is independent from the various parts that make up the object and how they are assembled.

The creation of the instances and their management are separated from each other so the program becomes simplest.

A very interesting aspect is that these mechanisms allow you to create an object step by step, checking its suitability at each step (think about when we want to build an object with data from the results of a parser) and above all it allows us to hide the control logic that would perhaps have been present in the possible manufacturer.

Let's give a definition:

The Builder Pattern is used to create instances of very complex objects with telescopic constructors in the simplest way

Let's look at the UML diagram of the Builder Pattern:

Builder pattern UML

Let's analyze in detail every component:

  • Product: it defines the type of object that will be generated from the Builder Pattern;
  • Builder: this abstract class defines the various steps needed in order to correctly create objects. Each method is generally abstract and implementations are provided by concrete subclasses. The getProduct () method is used to return the final product. Sometimes the Builder is replaced by an interface;
  • ConcreteBuilder: there may be different ConcreteBuilder concrete subclasses. These subclasses gives the mechanisms for the creation of complex objects;
  • Director: the Director class controls the algorithm for the objects creation. When it is instanciated, its constructor is invoked. It contains a parameter that indicates which ConcreteBuilder has to be used for creating objects. During the creation process, the various methods of the ConcreteBuilder are called and at the end of the operations, the getProduct() method is used in order to get the final product;

Let's look a possible structure in Java

Director

public class Director {
  public Director(Builder builder){
    builder.buildPart1();
    builder.buildPart2();
    builder.buildPart3();
    builder.getProduct();
  }
}

Builder

public abstract class Builder {
  public abstract void buildPart1();
  public abstract void buildPart2();
  public abstract void buildPart3();
  public abstract Product getProduct();
}

ConcreteBuilder

public class ConcreteBuilder extends Builder {
  private Product product;
  public ConcreteBuilder(){
    product=new Product();
  }
  @Override
  public void buildPart1() {
    product.setAttr1("attr1");
  }
  @Override
  public void buildPart2() {
    product.setAttr2("attr2");
  }
  @Override
   public void buildPart3() {
    product.setAttr3("attr3");
  }
  @Override
  public Product getProduct() {
    return product;
  }
}

Product

public class Product {
  public String attr1;
  public String attr2;
  public String attr3;
  public String getAttr1() {
    return attr1;
  }
  public void setAttr1(String attr1) {
    this.attr1 = attr1;
  }
  public String getAttr2() {
    return attr2;
  }
  public void setAttr2(String attr2) {
    this.attr2 = attr2;
  }
  public String getAttr3() {
    return attr3;
  }
  public void setAttr3(String attr3) {
    this.attr3 = attr3;
  }
}

Let's have a look to a possible use of the pattern. The example that I'm going to show comes from the book Effective Java written by Joshua Bloch. We state that in this particular case, the abstract Builder class is not strictly indispensable. It can be added as an exercise without radically changing the structure presented below.

import java.util.List;
     public class Animal {
     private final String id;
     private String name;
     private String pedigreeName;
     private String owner;
     private String race;
     private String residence;
     private Boolean isVaccinated;
     private Boolean isChampion;
     private List sons;
     private Sex sex;
     private Double weight;
     private Double height;
     public Animal(String name, String pedigreeName, String id, String owner, String race, String residence, Boolean isVaccinated, Boolean isChampion, List sons, Sex sex, Double weight, Double height) {
        this.name = name;
        this.pedigreeName = pedigreeName;
        this.id = id;
        this.owner = owner;
        this.race = race;
        this.residence = residence;
        this.isVaccinated = isVaccinated;
        this.isChampion = isChampion;
        this.sons = sons;
        this.sex = sex;
        this.weight = weight;
        this.height = height;
     }
     public Animal(String id, String name, String pedigreeName) {
        this.name = name;
        this.pedigreeName = pedigreeName;
        this.id = id;
     }
     public Animal(String id, String owner, String race, String residence) {
        this.id = id;
        this.owner = owner;
        this.race = race;
        this.residence = residence;
     }
     public Animal(String id) {
        this.id = id;
     }
     public enum Sex {
        MALE,
        FEMALE
     }
 }

Now we use the pattern

import java.util.List;

public final class AnimalBuilder {
    private String id;
    private String name;
    private String pedigreeName;
    private String owner;
    private String race;
    private String residence;
    private Boolean isVaccinated;
    private Boolean isChampion;
    private List<String> sons;
    private Animal.Sex sex;
    private Double weight;
    private Double height;

    private AnimalBuilder(String id) {
        this.id = id;
    }

    public static AnimalBuilder newBuilder(String id) {
        return new AnimalBuilder(id);
    }

    public AnimalBuilder name(String name) {
        this.name = name;
        return this;
    }

    public AnimalBuilder pedigreeName(String pedigreeName) {
        this.pedigreeName = pedigreeName;
        return this;
    }

    public AnimalBuilder owner(String owner) {
        this.owner = owner;
        return this;
    }

    public AnimalBuilder race(String race) {
        this.race = race;
        return this;
    }

    public AnimalBuilder residence(String residence) {
        this.residence = residence;
        return this;
    }

    public AnimalBuilder isVaccinated(Boolean isVaccinated) {
        this.isVaccinated = isVaccinated;
        return this;
    }

    public AnimalBuilder isChampion(Boolean isChampion) {
        this.isChampion = isChampion;
        return this;
    }

    public AnimalBuilder sons(List<String> sons) {
        this.sons = sons;
        return this;
    }

    public AnimalBuilder sex(Animal.Sex sex) {
        this.sex = sex;
        return this;
    }

    public AnimalBuilder weight(Double weight) {
        this.weight = weight;
        return this;
    }

    public AnimalBuilder height(Double height) {
        this.height = height;
        return this;
    }

    public Animal build() {
        return new Animal(name, pedigreeName, id, owner, race, residence, isVaccinated, isChampion, sons, sex, weight, height);
    }
}

An object can now be instanciates as follow.

Animal pluto2=AnimalBuilder.newBuilder("0000001")
        .name("0000001")
        .pedigreeName("PlutoSecondo")
        .owner("Marco Rossi")
        .race("labrador")
        .residence("Via x")
        .isVaccinated(true)
        .isChampion(false)
        .sons(null)
        .sex(Animal.Sex.MALE)
        .weight(40.5)
        .height(30.0)
        .build();

We can find different advantages in the use of this creational pattern, in fact we can create clone objects or very similar objects minimizing the code that has to be written. The used method is similar to the one shown below, referring to the builder created before:

Animal animal3A = animalBuilder.build();
Animal animal3AClone = animalBuilder.build();
Animal animal3B = animalBuilder.sex(Animal.Sex.FEMALE).build();

Here we create two identical objects and an object similar to the previous two, but with opposite sex. A very important advantage is that of concentrating class validation in a single method and therefore obtaining almost immutable objects.

Va precisato che la versione presentata è leggermente diversa da quella presentata nel modello originale. L'unico svantaggio dell'utilizzo del pattern è il fatto che vada necessariamente definita una classe builder per ogni oggetto, aumentando nettamente il tempo di sviluppo.

Must be said that the shown version is slightly different from the one shown in the original example. The only disadvantage of using the pattern is the fact that a builder class must necessarily be defined for each object, significantly increasing the development time.

A lot of IDEs have plugin for the management of builders. Personally, I use the IntelliJ plugin  Builder Generator.

By the way, in my opinion,it is always useful to have tools like this available wink

 
 
Alessio Mungelli

Alessio Mungelli

Computer Science student at UniTo (University of Turin), Network specializtion, blogger and writer. I am a kind of expert in Java desktop developement with interests in AI and web developement. Unix lover (but not Windows hater). I am interested in Linux scripting. I am very inquisitive and I love learning new stuffs.

 
 
 

Related Posts

Difference between arrow and normal functions in JavaScript

In this tutorial we are going to see how arrow functions differ from normal JavaScript functions. We will also see when you should use one and when you should use…

JavaScript Arrow functions: What they are and how to use them

In this article we are going to see what they are and how to use JavaScript Arrow Functions, a new feature introduced with the ES6 standard (ECMAScript 6). What are Arrow…

How to insert an element into an array with JavaScript

In this brief tutorial you will learn how to insert one or more elements into an array with JavaScript. For this we will use the splice function. The splice function will not…

What is the difference between primitives types and objects in JavaScript?

In this short tutorial we are going to look at the differences between primitive types and objects in JavaScript. To start with, we're going to look at what primitive types…

How to get DOM elements with JavaScript

When you access any element of the DOM, it is usual to save it in a variable. This is something that at first might seem very simple, but if you…

How to reverse an array in JavaScript

In this tutorial we are going to see how you can change the order of the elements of an array so that they are inverted. You could use a loop…

How synchronize the scroll of two divs with JavaScript

In case you have two divs of different sizes you may sometimes want to scroll both at the same time but at different speeds depending on their size. For example,…

How to use the codePointAt method in JavaScript

The JavaScript codePointAt method has more or less the same function as the charCodeAt method, used to get the 16-bit Unicode representation of the character at a certain position in…

How to check if a value is a number in JavaScript

In this short tutorial we are going to look at the various methods that exist to find out if a value is a number in JavaScript.   1. Using the isNaN() function   One…

How to use the charCodeAt method in JavaScript

The charCodeAt method is accepted by strings in JavaScript, returning the 16-bit Unicode code of the character at the position we pass as a parameter to the method. The charCodeAt method…

How to use the charAt method in JavaScript

The charAt method is accepted by strings in JavaScript, returning the position of the character passed as a parameter within the string. If the string contains multiple occurrences of the character…

Strings in JavaScript: What they are and how to use them

In this tutorial we are going to explain what strings are and how they are used in JavaScript. The tutorial is intended for people who are learning to program in…

We use our own and third-party cookies to improve our services, compile statistical information and analyze your browsing habits. This allows us to personalize the content we offer and to show you advertisements related to your preferences. By clicking "Accept all" you agree to the storage of cookies on your device to improve website navigation, analyse traffic and assist our marketing activities. You can also select "System Cookies Only" to accept only the cookies required for the website to function, or you can select the cookies you wish to activate by clicking on "settings".

Accept All Only sistem cookies Configuration