Open In App

Builder, Fluent Builder, and Faceted Builder Method Design Pattern in Java

Last Updated : 24 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Builder Pattern is defined as a creational design pattern that is used to construct a complex object step by step. It separates the construction of an object from its representation, allowing us to create different variations of an object with the same construction code. This pattern is particularly useful when dealing with a complex object with many optional parameters or configurations.

Use Cases of the Builder Pattern in Java

  • Fluent Interfaces: The Builder pattern is often used to create fluent interfaces, where method calls can be chained together to configure and build an object. This leads to code that reads like a DSL (domain-specific language), making it more intuitive and self-documenting.
  • Building Complex Objects: The most straightforward use case for the Builder pattern is when we need to create complex objects with many optional attributes. Instead of providing a constructor with numerous parameters, the Builder pattern allows us to set each attribute independently, resulting in more readable and maintainable code.
  • Configuring Immutable Objects: When dealing with immutable objects, such as String or LocalDate in Java, the Builder pattern can be used to create new instances with specific attribute values. Since immutable objects cannot be modified after creation, the Builder pattern provides an elegant way to configure them.
  • Testing Frameworks: Testing frameworks, such as JUnit and TestNG, often use the Builder pattern to create test cases and test configurations. Builders help simplify the setup and configuration of test cases, making test code more expressive.
  • UI Component Creation: Building user interface components like forms, dialogs, or menus can benefit from the Builder pattern. It allows us to specify various attributes and behaviors of these components in a structured manner.
  • Document Generation: In scenarios where we need to generate documents, reports, or other structured data, the Builder pattern can be used to create a document builder that facilitates the construction of the document’s elements in a modular and organized way.
  • Database Query Building: Building complex database queries with multiple conditions and parameters can be simplified using the Builder pattern. It allows us to construct SQL queries in a more readable and maintainable way.

Example of Builder Method in Java

Assume we have a ‘Person‘ class with several optional attributes like ‘firstName’, ‘lastName’, ‘age’, ‘address’, and ‘phone’. We can use the Builder pattern to create instances of ‘Person’ more intuitively and cleanly.

Key Component of Builder Design Pattern in Java

  1. First create a Builder class with methods for setting the optional parameters of the object that we want to create.
  2. Create a Director class (optional) that orchestrates the construction process by using the Builder.
  3. Create the Product class, which represents the complex object you want to build. This class should have a private constructor and a public static inner Builder class.

So here in this example the ‘Person‘ class has a nested ‘PersonBuilder‘ class, which allows us to set optional attributes using chained method calls. The ‘build‘ method creates a ‘Person‘ object with the specified attributes, and it enforces that required attributes like firstName and lastName are set.

Step wise Implementation for Builder Pattern in Java:

Let’s take a look at how the Builder pattern works in Java:

1. Create the Product Class:

First, we have to define the class for the product we want to build. This class should have attributes that need to be set during the construction process. These attributes can be optional or mandatory.

Java




public class Product {
    private String attribute1;
    private String attribute2;
    private int attribute3;
 
    // Constructor (usually private to enforce the use of the Builder)
    private Product(String attribute1, String attribute2, int attribute3) {
        this.attribute1 = attribute1;
        this.attribute2 = attribute2;
        this.attribute3 = attribute3;
    }
 
    // Getter methods
    public String getAttribute1() {
        return attribute1;
    }
 
    public String getAttribute2() {
        return attribute2;
    }
 
    public int getAttribute3() {
        return attribute3;
    }
}


2. Create the Builder Class

Next, we have to create a separate builder class for the product. The builder class has methods to set the various attributes of the product. It also contains a build method to create the final product instance.

Java




public class ProductBuilder {
    private String attribute1;
    private String attribute2;
    private int attribute3;
 
    public ProductBuilder setAttribute1(String attribute1) {
        this.attribute1 = attribute1;
        return this;
    }
 
    public ProductBuilder setAttribute2(String attribute2) {
        this.attribute2 = attribute2;
        return this;
    }
 
    public ProductBuilder setAttribute3(int attribute3) {
        this.attribute3 = attribute3;
        return this;
    }
 
    public Product build() {
        return new Product(attribute1, attribute2, attribute3);
    }
}


3. Using the Builder

To create a Product instance, we want to use the ProductBuilder class to set the desired attributes and then call the build method to obtain the final product.

Java




public class Main {
    public static void main(String[] args) {
        Product product = new ProductBuilder()
            .setAttribute1("Value1")
            .setAttribute2("Value2")
            .setAttribute3(42)
            .build();
 
        System.out.println("Product created with attributes:");
        System.out.println("Attribute1: " + product.getAttribute1());
        System.out.println("Attribute2: " + product.getAttribute2());
        System.out.println("Attribute3: " + product.getAttribute3());
    }
}


Overall Implementation for Builder Design in Java

Java




public class Person {
    private String firstName;
    private String lastName;
    private int age;
    private String address;
    private String phone;
 
    private Person(PersonBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.address = builder.address;
        this.phone = builder.phone;
    }
 
    // Getters for attributes
 
    public static class PersonBuilder {
        private String firstName;
        private String lastName;
        private int age;
        private String address;
        private String phone;
 
        public PersonBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
 
        public PersonBuilder age(int age) {
            this.age = age;
            return this;
        }
 
        public PersonBuilder address(String address) {
            this.address = address;
            return this;
        }
 
        public PersonBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
 
        public Person build() {
            return new Person(this);
        }
    }
 
    @Override
    public String toString() {
        return "Person [firstName=" + firstName + ", lastName=" + lastName + ", age=" + age + ", address=" + address
                + ", phone=" + phone + "]";
    }
 
    public static void main(String[] args) {
        Person person = new PersonBuilder("John", "Doe")
            .age(30)
            .address("123 Main St")
            .phone("555-1234")
            .build();
 
        System.out.println(person);
    }
}


Output

Person [firstName=John, lastName=Doe, age=30, address=123 Main St, phone=555-1234]


Diagrammatic Representation for Builder Design Pattern in Java

2023-11-07_8-44-03

working

So by using the Builder pattern, we can create a Product object step by step, setting only the attributes that are necessary, and leaving the others with default values or null if applicable. This approach makes the code more readable and allows for flexible construction of objects with various configurations. It also prevents the need for large constructors with multiple parameters and improves code maintainability.

What is Fluent Builder ?

A fluent builder is a design pattern in Java that allows us to create complex objects with a more readable and expressive syntax.

Uses of Fluent Builder:

It is often used to chain method calls together to configure and build an object. The key idea behind the fluent builder pattern is to return the builder itself from each method call, allowing us to chain method calls together in a fluent and intuitive way.

Example : we have a “pizza” class and there are various attributes of it. so there we will use the fluent builder pattern.

Java




public class Pizza {
    private String size;
    private boolean cheese;
    private boolean pepperoni;
    private boolean mushrooms;
 
    private Pizza() {
        // Private constructor to force the use of the builder
    }
 
    public static class PizzaBuilder {
        private Pizza pizza;
 
        public PizzaBuilder() {
            pizza = new Pizza();
        }
 
        public PizzaBuilder withSize(String size) {
            pizza.size = size;
            return this;
        }
 
        public PizzaBuilder withCheese(boolean cheese) {
            pizza.cheese = cheese;
            return this;
        }
 
        public PizzaBuilder withPepperoni(boolean pepperoni) {
            pizza.pepperoni = pepperoni;
            return this;
        }
 
        public PizzaBuilder withMushrooms(boolean mushrooms) {
            pizza.mushrooms = mushrooms;
            return this;
        }
 
        public Pizza build() {
            return pizza;
        }
    }
 
    @Override
    public String toString() {
        return "Pizza{" +
                "size='" + size + '\'' +
                ", cheese=" + cheese +
                ", pepperoni=" + pepperoni +
                ", mushrooms=" + mushrooms +
                '}';
    }
 
    public static void main(String[] args) {
        Pizza pizza = new PizzaBuilder()
                .withSize("Large")
                .withCheese(true)
                .withPepperoni(true)
                .withMushrooms(true)
                .build();
 
        System.out.println(pizza);
    }
}


Output

Pizza{size='Large', cheese=true, pepperoni=true, mushrooms=true}


Explanation of example :

In this example, we have a Pizza class with a nested PizzaBuilder class. The Pizza class has private fields for pizza properties like size, cheese, pepperoni, and mushrooms. The PizzaBuilder class provides methods to set these properties and then returns the built Pizza object. This allows us to create a Pizza object using a fluent and readable syntax.

Note: In the main method, we demonstrate how to use the Fluent Builder Pattern to create a Pizza object with various properties.

What is Faceted Builder?

The Faceted Builder is a design pattern that combines the Builder pattern with a fluent API to create a more expressive and readable way of constructing complex objects with multiple configuration options.

Uses of Faceted Builder:

Faceted Builder pattern is particularly useful when we have an object with a large number of configuration options, and we want to provide a clear and organized way to set those options. Instead of having a single builder class with many methods for configuring different attributes, we create multiple builder classes, each responsible for a specific set of attributes.

Further Read: Java Design Pattern Tutorial



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads