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

How to use the endsWith method in JavaScript

In this short tutorial, we are going to see what the endsWith method, introduced in JavaScript ES6, is and how it is used with strings in JavaScript. The endsWith method is…

What are javascript symbols and how can they help you?

Symbols are a new primitive value introduced by ES6. Their purpose is to provide us unique identifiers. In this article, we tell you how they work, in which way they…

Callbacks in JavaScript

Callback functions are the same old JavaScript functions. They have no special syntax, as they are simply functions that are passed as an argument to another function. The function that receives…

How to create PDF with JavaScript and jsPDF

Creating dynamic PDF files directly in the browser is possible thanks to the jsPDF JavaScript library. In the last part of this article we have prepared a practical tutorial where I…

How to make your own custom cursor for your website

When I started browsing different and original websites to learn from them, one of the first things that caught my attention was that some of them had their own cursors,…

Open source web design tools alternatives

There are many prototyping tools, user interface design tools or vector graphics applications. But most of them are paid or closed source. So here I will show you several open…

PHP - The Singleton Pattern

The Singleton Pattern is one of the GoF (Gang of Four) Patterns. This particular pattern provides a method for limiting the number of instances of an object to just one.…

Node.js and npm: introductory tutorial

In this tutorial we will see how to install and use both Node.js and the npm package manager. In addition, we will also create a small sample application. If you…

How to connect to MySQL with Node.js

Let's see how you can connect to a MySQL database using Node.js, the popular JavaScript runtime environment. Before we start, it is important to note that you must have Node.js installed…

JavaScript Programming Styles: Best Practices

When programming with JavaScript there are certain conventions that you should apply, especially when working in a team environment. In fact, it is common to have meetings to discuss standards…

Secret iPhone codes to unlock hidden features

We love that our devices have hidden features. It's fun to learn something new about the technology we use every day, to discover those little features that aren't advertised by the…

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…

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