Builder Design Pattern: Simplify Complex Object Construction
Design Pattern

Builder Design Pattern: Simplify Complex Object Construction

S

Shivam Chauhan

about 2 months ago

The Builder Design Pattern is a creational pattern that simplifies the construction of complex objects step by step. It separates the construction process from the representation, allowing you to create different types of objects using the same construction code.

In this blog, we'll explore:

  • What the Builder Design Pattern is.
  • When and why to use it.
  • How to implement it in Java with a practical example.
  • Key benefits and trade-offs of using the Builder Pattern.

What is the Builder Design Pattern?

The Builder Pattern helps construct complex objects by separating the construction logic from the object itself. This allows the same construction process to create different representations of the object.

Key Concepts:

  • Builder: Defines methods to set the parts of the object.
  • Concrete Builder: Implements the builder interface to construct and assemble the parts.
  • Director: Controls the construction process.
  • Product: The final object that’s constructed.

When to Use the Builder Pattern

Use the Builder Pattern when:

  • The object being constructed has a large number of optional parameters.
  • You want to make the construction process readable and maintainable.
  • You need to create different representations of the same object.

Real-World Example: Building a House

Let’s implement a House Builder where the final product (House) can have optional parts like a swimming pool, garage, and garden.

Builder Pattern in Java

java
// Product
class House {
    private String foundation;
    private String structure;
    private String roof;
    private boolean hasGarage;
    private boolean hasSwimmingPool;
    private boolean hasGarden;

    // Getters and toString for displaying house details
    public String toString() {
        return "House [foundation=" + foundation + ", structure=" + structure + ", roof=" + roof +
                ", hasGarage=" + hasGarage + ", hasSwimmingPool=" + hasSwimmingPool +
                ", hasGarden=" + hasGarden + "]";
    }

    // Builder Class
    public static class Builder {
        private String foundation;
        private String structure;
        private String roof;
        private boolean hasGarage;
        private boolean hasSwimmingPool;
        private boolean hasGarden;

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

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

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

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

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

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

        public House build() {
            House house = new House();
            house.foundation = this.foundation;
            house.structure = this.structure;
            house.roof = this.roof;
            house.hasGarage = this.hasGarage;
            house.hasSwimmingPool = this.hasSwimmingPool;
            house.hasGarden = this.hasGarden;
            return house;
        }
    }
}

// Client Code
public class Client {
    public static void main(String[] args) {
        // Build a luxury house
        House luxuryHouse = new House.Builder()
                .setFoundation("Concrete")
                .setStructure("Steel")
                .setRoof("Glass")
                .setGarage(true)
                .setSwimmingPool(true)
                .setGarden(true)
                .build();

        System.out.println(luxuryHouse);

        // Build a basic house
        House basicHouse = new House.Builder()
                .setFoundation("Wood")
                .setStructure("Brick")
                .setRoof("Tiles")
                .build();

        System.out.println(basicHouse);
    }
}

Explanation of Code:

  1. Product: The House class represents the complex object to be built.
  2. Builder: The House.Builder class contains methods to set optional properties and build the final object.
  3. Client Code: Demonstrates building different types of houses (luxury and basic) using the same construction logic.

Output:

plaintext
House [foundation=Concrete, structure=Steel, roof=Glass, hasGarage=true, hasSwimmingPool=true, hasGarden=true]
House [foundation=Wood, structure=Brick, roof=Tiles, hasGarage=false, hasSwimmingPool=false, hasGarden=false]

UML Diagram for Builder Design Pattern

Here’s the UML diagram for the House Builder example:

Drag: Pan canvas

Benefits of the Builder Pattern

  1. Readable Code: Simplifies the creation of complex objects with a fluent API.
  2. Flexibility: Allows the same construction process to create different representations.
  3. Immutability: Ensures the object is immutable once built.

Drawbacks of the Builder Pattern

  1. Overhead: Requires additional classes for the builder, which might add complexity for simple objects.
  2. Verbosity: Can lead to verbose code when the object has many optional parameters.

Conclusion

The Builder Design Pattern is an essential tool for constructing complex objects in a clean and maintainable way. It shines in scenarios where objects have numerous optional parameters, providing both flexibility and clarity.

By mastering the Builder Pattern, you'll write cleaner, more extensible code for real-world applications. Start incorporating this pattern in your projects to simplify object construction and improve maintainability.

About the Author

S

Shivam Chauhan

Sharing insights about system design and coding practices.