Builder design pattern in java

The builder design pattern in java is a creational design pattern because this pattern will help us to optimize the code and write a better piece of code to create an object of a class. In simple terms, this Builder design pattern helps us to create complex objects in an easier way.

Say we are having a class with 12 properties. Now to create an object of that class and to initialize all these properties we will create a parameterized constructor with all these 12 properties. Consider the below example

package com.builder;

public class PayoutDetails 
{
  String payerFirstName;

  String payerLastName;

  String payerAddressLine;

  String payerCity;

  String payerCountry;

  String beneficiaryFirstName;

  String beneficiaryLastName;

  String beneficiaryAddressLine;

  String beneficiaryCity;

  String beneficiaryCountry;

  double transferAmount;

  String currency;

  public PayoutDetails(String payerFirstName, String payerLastName, String payerAddressLine, String payerCity, String payerCountry, String beneficiaryFirstName, String beneficiaryLastName, String beneficiaryAddressLine, String beneficiaryCity, String beneficiaryCountry, double transferAmount, String currency) 
  {
    super();
    this.payerFirstName = payerFirstName;
    this.payerLastName = payerLastName;
    this.payerAddressLine = payerAddressLine;
    this.payerCity = payerCity;
    this.payerCountry = payerCountry;
    this.beneficiaryFirstName = beneficiaryFirstName;
    this.beneficiaryLastName = beneficiaryLastName;
    this.beneficiaryAddressLine = beneficiaryAddressLine;
    this.beneficiaryCity = beneficiaryCity;
    this.beneficiaryCountry = beneficiaryCountry;
    this.transferAmount = transferAmount;
    this.currency = currency;
  }

  @Override
  public String toString() 
  {
     return "PayoutDetails [payerFirstName=" + payerFirstName + ", payerLastName=" + payerLastName + ", payerAddressLine=" + payerAddressLine + ", payerCity=" + payerCity + ", payerCountry=" + payerCountry + ", beneficiaryFirstName=" + beneficiaryFirstName + ", beneficiaryLastName=" + beneficiaryLastName + ", beneficiaryAddressLine=" + beneficiaryAddressLine + ", beneficiaryCity=" + beneficiaryCity + ", beneficiaryCountry=" + beneficiaryCountry + ", transferAmount=" + transferAmount + ", currency=" + currency + "]";
  }
}
package com.builder;

public class Demo {

  public static void main(String[] args) {

    PayoutDetails payoutDetails = new PayoutDetails("Rohit", "Sharma", null, "Mumbai", "India", "Virat", "Kohli", null, "Delhi", "India", 1000, "INR");

    System.out.println(payoutDetails);
  }
}

Output : PayoutDetails [payerFirstName=Rohit, payerLastName=Sharma, payerAddressLine=null, payerCity=Mumbai, payerCountry=India, beneficiaryFirstName=Virat, beneficiaryLastName=Kohli, beneficiaryAddressLine=null, beneficiaryCity=Delhi, beneficiaryCountry=India, transferAmount=1000.0, currency=INR]

Drawbacks of code with constructor

  • We have to remember the sequence of variables and we have to enter those values in a sequence.
  • It can happen few fields are optional still we have to provide those values while creating the object. Ex. Say payerAddressLine and beneficiaryAddressLine are optional fields still as a developer we have to initialize its value at least by a null.
  • The above piece of code is quite difficult to read, as the number of fields increases the readability decreases.

Advantages of Builder design pattern

  • We do not have to remember the sequence of variables. The fields can be initialized in any manner.
  • It is not mandatory to initialize the optional fields. We can initialize only the mandatory properties leaving the optional ones.
  • Increases the readability of the code and easier to understand.
  • Builder design pattern helps us to create an object of a class using a step-by-step approach. The complete object will not be created at once it will be done in steps.

Please check the code below, we will keep the PayoutDetails class as it is

package com.builder;

public class PayoutDetails 
{
  String payerFirstName;

  String payerLastName;

  String payerAddressLine;

  String payerCity;

  String payerCountry;

  String beneficiaryFirstName;

  String beneficiaryLastName;

  String beneficiaryAddressLine;

  String beneficiaryCity;

  String beneficiaryCountry;

  double transferAmount;

  String currency;

  public PayoutDetails(String payerFirstName, String payerLastName, String payerAddressLine, String payerCity, String payerCountry, String beneficiaryFirstName, String beneficiaryLastName, String beneficiaryAddressLine, String beneficiaryCity, String beneficiaryCountry, double transferAmount, String currency) 
  {
    super();
    this.payerFirstName = payerFirstName;
    this.payerLastName = payerLastName;
    this.payerAddressLine = payerAddressLine;
    this.payerCity = payerCity;
    this.payerCountry = payerCountry;
    this.beneficiaryFirstName = beneficiaryFirstName;
    this.beneficiaryLastName = beneficiaryLastName;
    this.beneficiaryAddressLine = beneficiaryAddressLine;
    this.beneficiaryCity = beneficiaryCity;
    this.beneficiaryCountry = beneficiaryCountry;
    this.transferAmount = transferAmount;
    this.currency = currency;
  }

  @Override
  public String toString() 
  {
     return "PayoutDetails [payerFirstName=" + payerFirstName + ", payerLastName=" + payerLastName + ", payerAddressLine=" + payerAddressLine + ", payerCity=" + payerCity + ", payerCountry=" + payerCountry + ", beneficiaryFirstName=" + beneficiaryFirstName + ", beneficiaryLastName=" + beneficiaryLastName + ", beneficiaryAddressLine=" + beneficiaryAddressLine + ", beneficiaryCity=" + beneficiaryCity + ", beneficiaryCountry=" + beneficiaryCountry + ", transferAmount=" + transferAmount + ", currency=" + currency + "]";
  }
}

We will create a Builder class. In this class, we will set fields step by step. As soon as a field is set we will return the current reference of the Builder class. We will also have a get method that will return the object which we have created.

package com.builder;

public class PayoutDetailsBuilder {
	
  String payerFirstName;
	
	String payerLastName;
	
	String payerAddressLine;
	
	String payerCity;
	
	String payerCountry;
	
  String beneficiaryFirstName;
	
	String beneficiaryLastName;
	
	String beneficiaryAddressLine;
	
	String beneficiaryCity;
	
	String beneficiaryCountry;
	
	double transferAmount;
	
	String currency;
	
	public PayoutDetailsBuilder setPayerFirstName(String payerFirstName) {
		this.payerFirstName = payerFirstName;
		return this;
	}

	public PayoutDetailsBuilder setPayerLastName(String payerLastName) {
		this.payerLastName = payerLastName;
		return this;
	}

	public PayoutDetailsBuilder setPayerAddressLine(String payerAddressLine) {
		this.payerAddressLine = payerAddressLine;
		return this;
	}

	public PayoutDetailsBuilder setPayerCity(String payerCity) {
		this.payerCity = payerCity;
		return this;
	}

	public PayoutDetailsBuilder setPayerCountry(String payerCountry) {
		this.payerCountry = payerCountry;
		return this;
	}

	public PayoutDetailsBuilder setBeneficiaryFirstName(String beneficiaryFirstName) {
		this.beneficiaryFirstName = beneficiaryFirstName;
		return this;
	}

	public PayoutDetailsBuilder setBeneficiaryLastName(String beneficiaryLastName) {
		this.beneficiaryLastName = beneficiaryLastName;
		return this;
	}

	public PayoutDetailsBuilder setBeneficiaryAddressLine(String beneficiaryAddressLine) {
		this.beneficiaryAddressLine = beneficiaryAddressLine;
		return this;
	}

	public PayoutDetailsBuilder setBeneficiaryCity(String beneficiaryCity) {
		this.beneficiaryCity = beneficiaryCity;
		return this;
	}

	public PayoutDetailsBuilder setBeneficiaryCountry(String beneficiaryCountry) {
		this.beneficiaryCountry = beneficiaryCountry;
		return this;
	}

	public PayoutDetailsBuilder setTransferAmount(double transferAmount) {
		this.transferAmount = transferAmount;
		return this;
	}

	public PayoutDetailsBuilder setCurrency(String currency) {
		this.currency = currency;
		return this;
	}

	public PayoutDetails getPayoutDetails()
	{
		return new PayoutDetails(payerFirstName, payerLastName, payerAddressLine, payerCity, 
				payerCountry, beneficiaryFirstName, beneficiaryLastName, beneficiaryAddressLine, 
				beneficiaryCity, beneficiaryCountry, transferAmount, currency);
	}
}
package com.builder;

public class Demo {
	
	public static void main(String[] args) {
		
		PayoutDetails payoutDetails = new PayoutDetailsBuilder()
				.setPayerFirstName("Rohit")
				.setPayerLastName("Sharma")
				.setPayerCity("Mumbai")
				.setPayerCountry("India")
				.setBeneficiaryFirstName("Virat")
				.setBeneficiaryLastName("Kohli")
				.setBeneficiaryCity("Delhi")
				.setBeneficiaryCountry("India")
				.setTransferAmount(1000)
				.setCurrency("INR")
				.getPayoutDetails();
		
		System.out.println(payoutDetails);
	}
}

In the above example, we did not remember the sequence of the variables nor did we initialize the optional variables, as well as the code looks clean.

Disadvantages of Builder design pattern

  • Increased code. We have to create a separate builder class to initialize the variables.
  • If the pattern is misused. Say we have to initialize only a few fields then we should not use the builder design pattern instead go with a constructor.
  • If we forgot to initialize any mandatory fields then at runtime there are chances we might encounter a null pointer exception.

Here you will find the link of the above example https://github.com/getinputs/samples/tree/main/Builder-Design-Pattern

In this article, we have covered what is a builder design pattern in java and the advantages and disadvantages of a builder design pattern with a proper example. I hope you found this article interesting and valuable. Please share this article with your friends and help me grow. If you are having any concerns or questions about this article please comment below. If you want to get in touch with me please visit the Contact Me page and send an email.

Leave a Comment