Builder Pattern

The Builder Pattern is a creational design pattern used to construct complex objects step by step. It allows you to produce different types and representations of an object using the same construction process. This pattern is particularly useful when dealing with objects that have multiple attributes or configuration parameters, especially when some of them are optional or have default values.

Important Components

  1. Product: The complex object being built (e.g., a house, a car).
  2. Builder: An interface or abstract class defining steps to build the product.
  3. Concrete Builder: Implements the Builder interface, providing specific implementations for building parts of the product.
  4. Director (optional): Orchestrates the building process by calling the builder’s methods in a specific order.

How It Works

  • The Builder provides methods to set or configure parts of the product.
  • The Concrete Builder implements these methods to construct parts of the product and maintains the product’s state.
  • The Director (if used) controls the sequence of construction steps.
  • Once construction is complete, the builder returns the final product.

Sample Implementation

// Product
class House {
    private String foundation;
    private String structure;
    private String roof;

    public void setFoundation(String foundation) { this.foundation = foundation; }
    public void setStructure(String structure) { this.structure = structure; }
    public void setRoof(String roof) { this.roof = roof; }
    @Override
    public String toString() {
        return "House [foundation=" + foundation + ", structure=" + structure + ", roof=" + roof + "]";
    }
}

// Builder Interface
interface HouseBuilder {
    void buildFoundation();
    void buildStructure();
    void buildRoof();
    House getHouse();
}

// Concrete Builder
class ConcreteHouseBuilder implements HouseBuilder {
    private House house;

    public ConcreteHouseBuilder() {
        this.house = new House();
    }

    @Override
    public void buildFoundation() { house.setFoundation("Concrete Foundation"); }
    @Override
    public void buildStructure() { house.setStructure("Wooden Structure"); }
    @Override
    public void buildRoof() { house.setRoof("Tiled Roof"); }
    @Override
    public House getHouse() { return house; }
}

// Director
class HouseDirector {
    private HouseBuilder builder;

    public HouseDirector(HouseBuilder builder) {
        this.builder = builder;
    }

    public House construct() {
        builder.buildFoundation();
        builder.buildStructure();
        builder.buildRoof();
        return builder.getHouse();
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        HouseBuilder builder = new ConcreteHouseBuilder();
        HouseDirector director = new HouseDirector(builder);
        House house = director.construct();
        System.out.println(house);
    }
}Code language: JavaScript (javascript)

Use case and Implementation

Building a complex `LoanApplication` object with multiple steps and parameters, such as applicant details, loan type, and interest rates.

//BuilderDemo.java
class LoanApplication {
    // Attributes
    private String applicantName;
    private String applicantAddress;
    private double loanAmount;
    private String loanType;
    private double interestRate;
    // Constructor (private to enforce object construction via builder)
    private LoanApplication() {}
    // Getters
    public String getApplicantName() {
        return applicantName;
    }
    public String getApplicantAddress() {
        return applicantAddress;
    }
    public double getLoanAmount() {
        return loanAmount;
    }
    public String getLoanType() {
        return loanType;
    }
    public double getInterestRate() {
        return interestRate;
    }
    // Setters (optional for mutable attributes)
    public void setApplicantName(String applicantName) {
        this.applicantName = applicantName;
    }
    public void setApplicantAddress(String applicantAddress) {
        this.applicantAddress = applicantAddress;
    }
    public void setLoanAmount(double loanAmount) {
        this.loanAmount = loanAmount;
    }
    public void setLoanType(String loanType) {
        this.loanType = loanType;
    }
   public void setInterestRate(double interestRate) {
        this.interestRate = interestRate;
    }
    @Override
    public String toString() {
        return "LoanApplication{" +
                "applicantName='" + applicantName + '\'' +
                ", applicantAddress='" + applicantAddress + '\'' +
                ", loanAmount=" + loanAmount +
                ", loanType='" + loanType + '\'' +
                ", interestRate=" + interestRate +
                '}';
    }
    // Builder Class
    static class Builder {
        private String applicantName;
        private String applicantAddress;
        private double loanAmount;
        private String loanType;
        private double interestRate;
        public Builder(String applicantName, double loanAmount) {
            this.applicantName = applicantName;
            this.loanAmount = loanAmount;
        }
        public Builder applicantAddress(String applicantAddress) {
            this.applicantAddress = applicantAddress;
            return this;
        }
        public Builder loanType(String loanType) {
            this.loanType = loanType;
            return this;
        }
        public Builder interestRate(double interestRate) {
            this.interestRate = interestRate;
            return this;
        }
        public LoanApplication build() {
            LoanApplication loanApplication = new LoanApplication();
            loanApplication.applicantName = this.applicantName;
            loanApplication.applicantAddress = this.applicantAddress;
            loanApplication.loanAmount = this.loanAmount;
            loanApplication.loanType = this.loanType;
            loanApplication.interestRate = this.interestRate;
            return loanApplication;
        }
    }
}

public class BuilderDemo {
    public static void main(String[] args) {
        // Using the Builder to create a LoanApplication object
        LoanApplication loanApp1 = new LoanApplication.Builder("Mahesh", 10000.0)
                                    .applicantAddress("SV Street, Kadapa, AP")
                                    .loanType("Bussiness Loan")
                                    .interestRate(5.0)
                                    .build();

        LoanApplication loanApp2 = new LoanApplication.Builder("Chakrapani", 50000.0)
		                            .applicantAddress("SV Street, Mydukur, AP")
                                    .loanType("Home Loan")
                                    .interestRate(4.5)
                                    .build();

        // Displaying the created LoanApplication objects
        System.out.println("Loan Application 1:");
        System.out.println("Applicant Name: " + loanApp1.getApplicantName());
        System.out.println("Applicant Address: " + loanApp1.getApplicantAddress());
        System.out.println("Loan Amount: " + loanApp1.getLoanAmount());
        System.out.println("Loan Type: " + loanApp1.getLoanType());
        System.out.println("Interest Rate: " + loanApp1.getInterestRate());
        System.out.println("\nLoan Application 2:");
        System.out.println("Applicant Name: " + loanApp2.getApplicantName());
        System.out.println("Applicant Address: " + loanApp2.getApplicantAddress());
        System.out.println("Loan Amount: " + loanApp2.getLoanAmount());
        System.out.println("Loan Type: " + loanApp2.getLoanType());
        System.out.println("Interest Rate: " + loanApp2.getInterestRate());
    }
}

/*
C:\>javac BuilderDemo.java

C:\>java BuilderDemo
Loan Application 1:
Applicant Name: Mahesh
Applicant Address: SV Street, Kadapa, AP
Loan Amount: 10000.0
Loan Type: Bussiness Loan
Interest Rate: 5.0

Loan Application 2:
Applicant Name: Chakrapani
Applicant Address: SV Street, Mydukur, AP
Loan Amount: 50000.0
Loan Type: Home Loan
Interest Rate: 4.5
*/

Advantages

  • Encapsulation: Hides the internal representation of the product.
  • Flexibility: Allows different builders to create different product variations.
  • Readability: Simplifies object creation with many parameters.
  • Immutability: Can create immutable objects by returning a fully constructed product.

Disadvantages

  • Complexity: Increases code size with additional classes/interfaces.
  • Overhead: May be overkill for simple objects with few parameters.

When to Use

  • When an object requires many optional or complex configurations.
  • When you want to enforce a specific construction process.
  • When you need to create different representations of the same object type.

Real-World Example

  • Java’s StringBuilder class uses a builder-like approach to construct strings efficiently.
  • HTML or XML document construction where elements are added step by step.

The Builder Pattern is a valuable tool for constructing complex objects with multiple configuration options. It promotes cleaner code by separating the construction logic from the main object and allows flexibility in creating different object configurations using the same building process.

Scroll to Top