DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Builder Design Pattern in Java
  • Object Relational Behavioral Design Patterns in Java
  • Distribution Design Patterns in Java - Data Transfer Object (DTO) And Remote Facade Design Patterns
  • Context Object Design Pattern in Java: Introduction and Key Points

Trending

  • Advancing Your Software Engineering Career in 2025
  • Intro to RAG: Foundations of Retrieval Augmented Generation, Part 2
  • Using Java Stream Gatherers To Improve Stateful Operations
  • Implementing API Design First in .NET for Efficient Development, Testing, and CI/CD
  1. DZone
  2. Coding
  3. Languages
  4. The Builder Design Pattern in Java

The Builder Design Pattern in Java

Want to learn more about the Builder design pattern in Java. Take a look at this post on using the Builder design pattern and why we need it.

By 
Kun Zhou user avatar
Kun Zhou
·
Oct. 22, 18 · Presentation
Likes (39)
Comment
Save
Tweet
Share
90.8K Views

Join the DZone community and get the full member experience.

Join For Free

Today, we will look into Builder pattern in Java. The Builder pattern is a creational pattern that can be used to create and configure objects.

Why Do We Need the Builder Pattern?

Suppose that you have a class with a handful of instance attributes, such as the Employee class shown below. In this class, some of the instance attributes are required while the rest are optional. What kind of constructors should you write for such a class? A first option would be to have a constructor that only takes the required attributes as parameters, one that takes all the required attributes plus the first optional one, another one that takes two optional attributes, and so on ( this is called telescoping constructor pattern). Then, your class will look something like below:

public class Employee {

    private final String firstName; //required
    private final String lastName;  //required
    private final int age;          //required
    private final int personalId;   //required
    private final String phone;     //optional
    private final String address;   //optional
    private final String mail;      //optional

    public Employee(String firstName, String lastName, int age, int personalId) {
        this(firstName, lastName, age, personalId, "", "");
    }

    public Employee(String firstName, String lastName, int age, int personalId, String phone) {
        this(firstName, lastName, age, personalId, phone, "");
    }

    public Employee(String firstName, String lastName, int age, int personalId, String phone, String address) {
        this(firstName, lastName, age, personalId, phone, address, "");
    }

    public Employee(String firstName, String lastName, int age, int personalId, String phone, String address, String mail) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.personalId = personalId;
        this.phone = phone;
        this.address = address;
        this.mail = mail;
    }
}


As developers, we offer a solution for clients to construct objects from the Employee class. But, clients may return with a bunch of questions for us, including:

  • Which constructor should I invoke? The one with four parameters or the one with five or six?
  • What is the default value for those optional parameters if I don’t pass a value for each?
  • If I want to pass values only for mail and phone but not for address, how can I fulfill this requirement?
  • What will happen if I mistakenly pass the value intended for the address to mail (compile may not complain about it because they have the same type)?

You might be thinking that the JavaBean pattern could be the second alternative solution to the above questions. In the JavaBeans pattern, we call a no-arg constructor to create an object and then call the setter method on this object to set each required parameter value and each optional parameter of your interest (as shown below). It is no surprise that the JavaBean pattern increases the readability of code and the flexibility of object construction. But, this solution has two big disadvantages: the first one is that the object state will be inconsistent unless all the attributes are set explicitly; the second one is that the JavaBean pattern makes a class mutable and requires extra efforts of developers to ensure thread safety.

Note: the final modifier has to be removed when using the JavaBean Pattern.

public class Employee {

    private  String firstName;  //required
    private  String lastName;   //required
    private  int age;           //required
    private  int personalId;    //required
    private  String phone;      //optional
    private  String address;    //optional
    private  String mail;       //optional

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setPersonalId(int personalId) {
        this.personalId = personalId;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void setMail(String mail) {
        this.mail = mail;
    }
}


Now we come to the third alternative solution: The Builder Pattern. The builder pattern takes the advantages of the safety of telescoping constructor pattern and readability of JavaBean pattern.

What Is the Builder Pattern?

First, Let’s see how we can implement a builder design pattern.

  1. First of all, you need to create a public static nested class, which has all the instance attributes from the outer class. The naming convention for Builder usually is that and if the class name is Employee, then the builder class should be named as EmployeeBuilder.
  2. The outer class Employee should have a private constructor that takes a EmployeeBuilder object as its argument.
  3. The builder class should have a public constructor with all the required attributes as parameters and these required attributes are defined as "final," which have setter methods to set the optional parameters. It should return the same Builder object after setting the optional attribute.
  4. The final step is to provide a build() method in the builder class that will return the outer class object to the client. This build() method will call the private constructor in the outer class, passing the Builder object itself as the parameter to this private constructor.
  5. The Employee class has only getter methods and no public constructor. So, the only way to get an Employee object is through the nested EmpolyeeBuilder class.

The redesigned class using Builder pattern will look like this:

package main.builderPattern;

public class Employee {

    private final String firstName;    //required
    private final String lastName;    //required
    private final int age;    //required
    private final int personalId; // required
    private final String phone;    //optional
    private final String address;    //optional
    private final String mail;    //optional

    public static class EmployeeBuilder {
        private final String firstName;    //required
        private final String lastName;    //required
        private final int age;    //required
        private final int personalId; // required
        private String phone;    //optional
        private String address;    //optional
        private String mail;    //optional

        public EmployeeBuilder(String firstName, String lastName, int age, int personalId) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.age = age;
            this.personalId = personalId;
        }

        public EmployeeBuilder setAddress(String address) {
            this.address = address;
            return this;
        }

        public EmployeeBuilder setPhone(String phone) {
            this.phone = phone;
            return this;
        }

        public EmployeeBuilder setMail(String mail) {
            this.mail = mail;
            return this;
        }

        public Employee build() {
            // call the private constructor in the outer class
            return new Employee(this);
        }
    }

    private Employee(EmployeeBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.personalId = builder.personalId;
        this.phone = builder.phone;
        this.address = builder.address;
        this.mail = builder.mail;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public int getPersonalId() {
        return personalId;
    }

    public String getPhone() {
        return phone;
    }

    public String getAddress() {
        return address;
    }

    public String getMail() {
        return mail;
    }
}


We can create an Employee object from client code as follows:

public class EmployeeTest {
    public static void main(String[] args) {
        Employee employee = new Employee.EmployeeBuilder("Cristiano", "Ronaldo", 33, 7)
                .setPhone("0045-1234556")
                .setAddress("Juventus")
                .setMail("CR@Juventus.org").build();
    }

}


You can see that client code is easy to write and read. But, nothing is perfect; the Builder pattern has its own disadvantages, like being more verbose than the telescoping constructor pattern.

Summary

Keep in mind that if your class has multiple attributes with the same type or optional when you design your class, it is time to consider the Builder Pattern. If now, you may want to add more parameters to your class, then it is never too late to consider refactoring your code with the Builder pattern.

To wrap up this post, I would like to cite some words from Joshua Bloch's Effective Java:

" The Builder pattern is a good choice when degsigning classes whose constructors or static factories would have more than a handful of parameters, espectially if many of the parameters are optional or of identical type"

That's it for now. Feel free to drop a comment if you have anything to ask or to add!

Builder pattern Design Java (programming language) Object (computer science) Attribute (computing)

Opinions expressed by DZone contributors are their own.

Related

  • Builder Design Pattern in Java
  • Object Relational Behavioral Design Patterns in Java
  • Distribution Design Patterns in Java - Data Transfer Object (DTO) And Remote Facade Design Patterns
  • Context Object Design Pattern in Java: Introduction and Key Points

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!