Builder Design Pattern

Nivedita KumariNivedita Kumari
5 min read

The Builder Design Pattern is a creational design pattern. The Builder Pattern helps to create complex objects step by step while keeping the construction process separate from the actual object. This makes the design more flexible, modular, and easy to maintain.

Why Use the Builder Pattern?

  1. Avoids too many constructors – Instead of creating multiple constructors with different parameters, we use a builder to construct objects in a readable way.

  2. Modular design – Different parts of an object can be built separately.

  3. Easier to extend – We can add new types of objects (builders) without changing existing code.

  4. Better control – We can control how an object is built step by step.

Key Components of the Builder Pattern

  • Product → The actual object that is being built (e.g., House, Computer, Car).

  • Builder Interface → Defines the blueprint (steps) to build the product.

  • Concrete Builder → Implements the steps to construct different versions of the product.

  • Director → Manages the construction process using a specific builder.

  • Client → Uses the builder (or director) to create the product.

Example

Product

package DesignPatterns.Creational.Builder.House;

//Product
public class House {
    private String type;
   private double area;
   private Integer bedrooms;
   private Integer bathrooms;
   private Integer floors;
   private Boolean garden;

    public void setType(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setArea(double area) {
        this.area = area;
    }

    public void setBathrooms(Integer bathrooms) {
        this.bathrooms = bathrooms;
    }

    public void setBedrooms(Integer bedrooms) {
        this.bedrooms = bedrooms;
    }

    public void setFloors(Integer floors) {
        this.floors = floors;
    }

    public void setGarden(Boolean garden) {
        this.garden = garden;
    }

    public Boolean getGarden() {
        return garden;
    }

    public double getArea() {
        return area;
    }

    public Integer getBathrooms() {
        return bathrooms;
    }

    public Integer getBedrooms() {
        return bedrooms;
    }

    public Integer getFloors() {
        return floors;
    }
}

Builder Interface

package DesignPatterns.Creational.Builder.House;

public interface HouseBuilder {
    void buildType();
    void buildArea();
    void buildBedrooms();
    void buildFloors();
    void buildBahtRooms();
    void buildGarden();
    House build();

}

Concrete Builders

package DesignPatterns.Creational.Builder.House;

public class ApartmentBuilder implements  HouseBuilder{
    private House house;


    ApartmentBuilder() {
        house  = new House();
    }
    @Override
    public void buildType() {
        this.house.setType("Apartment");

    }

    @Override
    public void buildArea() {
        this.house.setArea(1200.5);

    }

    @Override
    public void buildBedrooms() {
        this.house.setBedrooms(3);

    }

    @Override
    public void buildFloors() {
        this.house.setFloors(1);

    }

    @Override
    public void buildBahtRooms() {
        this.house.setBathrooms(3);

    }

    @Override
    public void buildGarden() {
        this.house.setGarden(false);

    }

    @Override
    public House build() {
        System.out.println("Type: " + house.getType() + " " + "Floors: " + house.getFloors() + " "+
        "BedRooms: " + house.getBedrooms() + " "+ "BathRooms: " + house.getBathrooms() + " "+
        "Garden: " + house.getGarden());
        return this.house;
    }
}
package DesignPatterns.Creational.Builder.House;

public class BungalowBuilder implements HouseBuilder{
    private House house;

    BungalowBuilder() {
        this.house = new House();
    }
    @Override
    public void buildType() {
        this.house.setType("Bungalow");
    }

    @Override
    public void buildArea() {
        this.house.setArea(2500.0);

    }

    @Override
    public void buildBedrooms() {
        this.house.setBedrooms(4);

    }

    @Override
    public void buildFloors() {
        this.house.setFloors(1);

    }

    @Override
    public void buildBahtRooms() {
        this.house.setBathrooms(3);

    }

    @Override
    public void buildGarden() {
        this.house.setGarden(true);

    }

    @Override
    public House build() {
        System.out.println("Type: " + house.getType() + " " + "Floors: " + house.getFloors() + " "+
                "BedRooms: " + house.getBedrooms() + " "+ "BathRooms: " + house.getBathrooms() + " "+
                "Garden: " + house.getGarden());
        return this.house;
    }
}
package DesignPatterns.Creational.Builder.House;

public class VillaBuilder implements  HouseBuilder{
    private House house;

    VillaBuilder() {
        this.house = new House();
    }
    @Override
    public void buildType() {
        this.house.setType("Villa");
    }

    @Override
    public void buildArea() {
        this.house.setArea(3500.0);

    }

    @Override
    public void buildBedrooms() {
        this.house.setBedrooms(5);

    }

    @Override
    public void buildFloors() {
        this.house.setFloors(2);

    }

    @Override
    public void buildBahtRooms() {
        this.house.setBathrooms(4);

    }

    @Override
    public void buildGarden() {
        this.house.setGarden(true);

    }

    @Override
    public House build() {
        System.out.println("Type: " + house.getType() + " " + "Floors: " + house.getFloors() + " "+
                "BedRooms: " + house.getBedrooms() + " "+ "BathRooms: " + house.getBathrooms() + " "+
                "Garden: " + house.getGarden());
        return this.house;
    }
}

Director

package DesignPatterns.Creational.Builder.House;

public class HouseDirector {
    public House constructHouse(HouseBuilder houseBuilder) {
        houseBuilder.buildType();
        houseBuilder.buildArea();
        houseBuilder.buildFloors();
        houseBuilder.buildBedrooms();
        houseBuilder.buildBahtRooms();
        houseBuilder.buildGarden();
        return houseBuilder.build();

    }
}

Client

package DesignPatterns.Creational.Builder.House;

public class Client {
    public static void main(String[] args) {
        HouseDirector houseDirector = new HouseDirector();
        ApartmentBuilder apartmentBuilder  = new ApartmentBuilder();
        BungalowBuilder bungalowBuilder = new BungalowBuilder();
        VillaBuilder villaBuilder = new VillaBuilder();
        System.out.println("Constructing an Apartment:");
        houseDirector.constructHouse(apartmentBuilder);
        System.out.println("Constructing a Villa:");
        houseDirector.constructHouse(villaBuilder);
        System.out.println("Constructing a Bungalow:");
        houseDirector.constructHouse(bungalowBuilder);

    }
}

Pros (Advantages)

  1. Improves Readability & Maintainability

  • Without Builder: Large constructors with many parameters are hard to read.

  • With Builder: Each step is clear and modular (buildType(), buildArea(), etc.), making the code easier to understand.


  1. Solves Telescoping Constructor Problem

  • If an object has many optional parameters, we usually create multiple constructors (constructor overloading), which becomes hard to manage.

  • Builder Pattern removes the need for multiple constructors and allows setting only the required parameters.


  1. Enforces Step-by-Step Object Construction

  • Ensures valid object state before returning the final object.

  • The Director enforces a sequence for building complex objects.


  1. Supports Multiple Representations of an Object

  • The same HouseBuilder interface can be implemented differently (e.g., ApartmentBuilder, VillaBuilder, BungalowBuilder).

  • Flexibility: You can add more builders without modifying existing ones.


  1. Improves Code Modularity

  • Separates object creation logic (Builder classes) from the object usage (Client class).

  • Easy to modify/add new features without affecting client code.


Cons (Disadvantages)

  1. More Code Overhead (Boilerplate Code)

  • Compared to simple constructors, the Builder Pattern requires extra classes (Builder, ConcreteBuilder, Director).

  • Not useful for small/simple objects where a constructor is enough.


  1. Increased Complexity for Simple Objects

  • If an object has only 2-3 parameters, using a builder adds unnecessary complexity instead of simplifying.

  1. Requires Strict Order for Building

  • If the Director follows a strict sequence (buildType() → buildArea() → buildBedrooms()), then:

    • Customizing object creation becomes harder.

    • Clients may need custom builders for different sequences.


  1. Not Always Memory Efficient

  • The Builder class holds references to partially built objects, consuming extra memory during object creation.
10
Subscribe to my newsletter

Read articles from Nivedita Kumari directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Nivedita Kumari
Nivedita Kumari

I am wokring as SDE-1 at BetterPlace