Home Tutorials Training Consulting Books Company Contact us


Get more...

This article describes the Builder design pattern and its implementation in the programming language Java.

1. The Builder Pattern

1.1. Definition

The Builder Pattern provides a dedicated object, called the builder, which is used to construct a complex object, known as the product. It encapsulates the logic for assembling the various parts of the product in a controlled manner.

Typically, the Builder Pattern is implemented by a class that contains several methods for configuring the product. These methods usually return the builder object itself, enabling a fluent API, where methods can be chained together in a readable, sequential flow. Once the product is fully configured, a build() method is invoked to create the final object.

The builder can be implemented as an inner class or as a separate class.

For simpler objects, or when the builder is closely tied to the product and likely won’t be reused, it is recommended to use an inner class. This keeps everything encapsulated and prevents unnecessary exposure of the code.

For more complex objects, or when you anticipate the builder being reused across different products or parts of the project, implementing the builder as a separate class offers more flexibility and modularity in your codebase.

1.2. Example

In this example, we have a Task class that acts as the product. It contains a builder implemented as an inner class.

package com.vogella.model.task;

import java.util.Date;

public class Task {
    private final long id;
    private String summary = "";
    private String description = "";
    private boolean done = false;
    private Date dueDate;

    // Constructor with mandatory field
    public Task(long id) {
        this.id = id;
    }
    
    // Private constructor for Builder
    private Task(Builder builder) {
        this.id = builder.id;
        this.summary = builder.summary;
        this.description = builder.description;
        this.done = builder.done;
        this.dueDate = builder.dueDate;
    }
    
    // Getters and Setters
    public long getId() {
        return id;
    }

    public String getSummary() {
        return summary;
    }

    public String getDescription() {
        return description;
    }

    public boolean isDone() {
        return done;
    }

    public Date getDueDate() {
        return new Date(dueDate.getTime());
    }

    // Builder Inner Class
    public static class Builder {
        private final long id; // mandatory field
        private String summary = "";
        private String description = "";
        private boolean done = false;
        private Date dueDate;

        // Builder constructor with required field
        public Builder(long id) {
            this.id = id;
        }

        // Setters for optional fields
        public Builder summary(String summary) {
            this.summary = summary;
            return this;
        }

        public Builder description(String description) {
            this.description = description;
            return this;
        }

        public Builder done(boolean done) {
            this.done = done;
            return this;
        }

        public Builder dueDate(Date dueDate) {
            this.dueDate = new Date(dueDate.getTime());
            return this;
        }

        // Build method to create the Task object
        public Task build() {
            return new Task(this);
        }
    }
}

Here’s an example of how to use this builder:

Task task = new Task.Builder(1)
    .summary("New Task")
    .description("This is a description")
    .done(false)
    .dueDate(new Date())
    .build();

1.3. Evaluation

The Builder Pattern simplifies object creation, especially when dealing with complex objects. It also streamlines the code by eliminating the need for complex constructors or multiple setter calls.

Additionally, the Builder Pattern is useful for creating immutable objects, which can make your code more robust and predictable.

2. Links and Literature