Builder Pattern is a creational design pattern that lets you construct complex objects having different representations using the same construction process.

Structure

The Builder pattern consists of the following key components:

  • Builder: is an abstract class or interface that declares product construction steps common to all the builders
  • Concrete Builders: provides different implementations for the Builder interface, each providing different representations of the Product object
  • Product: class represents the complex object which the builders generate
  • Directors: class defines steps for building the different representations of the Product object
  • Client: uses objects returned by the Director class

When to use Builder Pattern?

  • When you want to encapsulate the object-construction logic in a separate class, i.e, the builder class (Single Responsibility Principle)
  • When you want to add new representations of Product objects to the application in the future (Open/Closed Principle)
  • When you want to use different representations of the same product
  • When you want to simplify the object construction process and keep all the object construction code separate instead of keeping it in a single constructor or multiple constructors for different representations

Implementation Example

The code below demonstrates the implementation of the Builder design pattern in Java. The Builder pattern is used to construct complex objects step by step, allowing for different representations of the same object.

In this example, the Director class defines the steps to construct single and double patty burgers using the Builder interface. The BurgerBuilder class provides a concrete implementation of the Builder interface, specifying how to add buns, patties, toppings, and sauces to the burger. The Burger class represents the final product, which is constructed by the BurgerBuilder.

import java.util.*;

// client class
public class Solution {
    
    public static void main(String[] args) {
        
        Director director = new Director();
        Builder builder = new BurgerBuilder();

        director.constructSinglePattyBurger(builder);
        System.out.println(builder.getBurger().toString());

        director.constructDoublePattyBurger(builder);
        System.out.println(builder.getBurger().toString());
    }
}

// the director class, this can also be done directly in the client code
class Director {

    public void constructSinglePattyBurger(Builder builder) {

        builder.reset();
        builder.addBuns();
        builder.addPatty(1);
        builder.addToppings(3);
        builder.addSauces(3);
    }

    public void constructDoublePattyBurger(Builder builder) {

        builder.reset();
        builder.addBuns();
        builder.addPatty(2);
        builder.addToppings(2);
        builder.addSauces(2);
    }
}

// builder interface declaring the steps for creating an object
interface Builder {

    public abstract void addBuns();
    public abstract void addPatty(int count);
    public abstract void addToppings(int count);
    public abstract void addSauces(int count);

    public abstract void reset();
    public abstract Burger getBurger();
}

// concrete implementation of the Builder interface
class BurgerBuilder implements Builder {

    private Burger burger;

    public BurgerBuilder() {

        reset();
    }

    public void addBuns() {

        burger.addIngredient("2 Buns");
    }

    public void addPatty(int count) {
        
        burger.addIngredient(count + " patties");
    }

    public void addToppings(int count) {

        burger.addIngredient(count + " toppings");
    }

    public void addSauces(int count) {

        burger.addIngredient(count + " sauces");
    }

    public void reset() {

        burger = new Burger();
    }

    public Burger getBurger() {

        return burger;
    }
}

// the product whose object we will get from Builder
class Burger {

    private List<String> ingredients = new ArrayList<>();

    public void addIngredient(String ingredient) {
        
        ingredients.add(ingredient);
    }

    public String toString() {
        
        return "Your burger have the following items: " + Arrays.toString(ingredients.toArray());
    }
}

The output of the following program will be:

Your burger have the following items: [2 Buns, 1 patties, 3 toppings, 3 sauces]
Your burger have the following items: [2 Buns, 2 patties, 2 toppings, 2 sauces]