MOBI BOOT CAMP CORP. logoLearning Buddy
  • SIGN IN
  • Introduction
  • 1. Build Tools & Project Structure
  • 2. The Web Layer (Servlets & JSP)
  • 3. Design Patterns & Architecture
    • Architectural Patterns (MVC, DAO, DTO)
    • Singleton Pattern
    • Factory Method Pattern
    • Builder Pattern
    • Strategy Pattern
    • Observer Pattern
  • 4. Persistence Foundations (SQL & JDBC)
  • 5. Object-Relational Mapping (ORM)
  • 6. Modern Web Services & Microservices
  • 7. Hands-on Project

Builder Pattern

The Builder Pattern is a creational design pattern used to construct a complex object step by step. It separates the construction of a complex object from its representation, so the same construction process can create different representations.

This pattern is extremely useful when you need to create an object with many possible configuration options or optional fields. It helps avoid the "telescoping constructor" anti-pattern (having multiple constructors with different parameter lists) and improves code readability.

When to Use It

  • When the constructor for a class would have a large number of parameters, most of which might be optional.
  • When you want to create an object that requires a multi-step setup.
  • When you need to create immutable objects without having a complex, all-encompassing constructor.

Structure

  1. Product: The complex object that is being built.
  2. Builder: An interface that specifies the steps for building the Product.
  3. ConcreteBuilder: Implements the Builder interface and provides the logic for constructing the parts of the Product. It keeps track of the representation it's creating.
  4. Director (Optional): A class that defines the order in which to execute the building steps. It works with a builder object through the common Builder interface.

In modern Java, the Director is often omitted, and the client code calls the builder's steps directly in a fluent "chaining" style.


Example: Building an Email Object

Consider an Email object that can have many optional fields like cc, bcc, subject, and body. Using a constructor would be cumbersome. The Builder pattern is a perfect fit.

1. Product Class (Email)

This is the complex object we want to create. Note that its constructor is private, forcing the use of the builder.

package com.example.patterns.builder;

public class Email {
    private final String to;       // required
    private final String from;     // required
    private final String subject;  // optional
    private final String body;     // optional
    private final String cc;       // optional
    private final String bcc;      // optional

    // Private constructor that takes a builder
    private Email(EmailBuilder builder) {
        this.to = builder.to;
        this.from = builder.from;
        this.subject = builder.subject;
        this.body = builder.body;
        this.cc = builder.cc;
        this.bcc = builder.bcc;
    }

    @Override
    public String toString() {
        return "Email{" +
                "to='" + to + "\'" +
                ", from='" + from + "\'" +
                ", subject='" + subject + "\'" +
                ", body='" + body + "\'" +
                ", cc='" + cc + "\'" +
                ", bcc='" + bcc + "\'" +
                "}";
    }

    // Static nested Builder class
    public static class EmailBuilder {
        private final String to;
        private final String from;
        private String subject;
        private String body;
        private String cc;
        private String bcc;

        // Builder constructor for the required fields
        public EmailBuilder(String to, String from) {
            this.to = to;
            this.from = from;
        }

        // Setter methods for optional fields that return the builder
        public EmailBuilder withSubject(String subject) {
            this.subject = subject;
            return this; // Return the builder for method chaining
        }

        public EmailBuilder withBody(String body) {
            this.body = body;
            return this;
        }

        public EmailBuilder withCc(String cc) {
            this.cc = cc;
            return this;
        }

        public EmailBuilder withBcc(String bcc) {
            this.bcc = bcc;
            return this;
        }

        // The final build() method that returns the Email object
        public Email build() {
            return new Email(this);
        }
    }
}

2. Putting It All Together

The client code uses the EmailBuilder to construct an Email object in a highly readable, fluent way.

package com.example.patterns.builder;

public class BuilderDemo {
    public static void main(String[] args) {
        // Create a simple email with only required fields
        Email simpleEmail = new Email.EmailBuilder("recipient@example.com", "sender@example.com")
                .build();
        System.out.println("Simple Email: " + simpleEmail);

        System.out.println("---");

        // Create a complex email with several optional fields
        Email complexEmail = new Email.EmailBuilder("recipient@example.com", "sender@example.com")
                .withSubject("Project Update")
                .withBody("Here is the latest update on the project...")
                .withCc("manager@example.com")
                .build();
        System.out.println("Complex Email: " + complexEmail);
    }
}

Output:

Simple Email: Email{to='recipient@example.com', from='sender@example.com', subject='null', body='null', cc='null', bcc='null'}
---
Complex Email: Email{to='recipient@example.com', from='sender@example.com', subject='Project Update', body='Here is the latest update on the project...', cc='manager@example.com', bcc='null'}

The Modern Approach: Project Lombok

Manually writing a builder class can be repetitive. Project Lombok is a popular library that can automatically generate the builder pattern for you with a single annotation.

To use it, you would add the Lombok dependency to your pom.xml and write your Email class like this:

import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class EmailLombok {
    @Builder.Default private final String from = "default.sender@example.com";
    private final String to;
    private final String subject;
    private final String body;
    private final String cc;
    private final String bcc;
}

Lombok automatically generates the EmailLombokBuilder class and the builder() method at compile time, which you can use just like the manual version:

EmailLombok email = EmailLombok.builder()
    .to("recipient@example.com")
    .subject("Hello from Lombok!")
    .build();

System.out.println(email);

This significantly reduces boilerplate code and is the preferred way to implement the Builder pattern in modern Java projects.

Privacy Policy | Terms & Conditions