Builder: Design Pattern

Dec 20, 2022 By Puneet verma

The builder pattern is a creational design pattern that allows for the creation of complex objects through the use of a step-by-step construction process.

It is particularly useful when dealing with objects with many optional parameters. It allows you to create the object piece by piece rather than specifying all the parameters at once.

Instead of creating an object directly, the client calls a builder object's methods to create the object piece by piece. The Builder pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.

It can be especially useful when the object being constructed has multiple representations or when the construction process needs to be separated from the object's representation.

This can be useful in cases where the object is required to be constructed in a specific way, but the exact details of how it is represented may need to change over time.

Another advantage of the builder pattern is that it can make it easier to create objects in a fluent style, as you can chain together method calls to build the object step by step. This can make the code more readable and easier to understand, especially in cases where there are many optional parameters that need to be set.

Overall, the builder pattern is a useful tool for creating complex objects in a flexible and maintainable way.

Here are a few practical examples of the Builder pattern:

  1. Building a car: The process of building a car can be quite complex, involving the assembly of various parts such as the engine, transmission, and body. The Builder pattern can be used to create different representations of a car, such as a sports car or a luxury car, using the same construction process.

  2. Creating a document: A document can have different representations, such as a PDF or a Word document. The Builder pattern can be used to create these different representations using the same construction process.

  3. Generating HTML pages: The Builder pattern can be used to generate HTML pages with different layouts and content using the same construction process.

  4. Creating a game level: In a video game, the Builder pattern can be used to create different levels with different layouts and challenges, using the same construction process.

These are just a few examples of how the Builder pattern can be used in practice. The pattern can be useful in any situation where the construction of an object is complex and needs to be separated from the object's representation.

Let's take an example to understand it better.

Imagine you are building a custom home and have hired a home builder to oversee the construction process. The home builder works with a team of subcontractors to build the various parts of the home.

Here's some example code that represents this scenario:

class HomeBuilder
{
    private $subcontractors;
 
    public function __construct()
    {
        $this->subcontractors = [];
    }
 
    public function addSubcontractor(Subcontractor $subcontractor)
    {
        $this->subcontractors[] = $subcontractor;
    }
 
    public function buildHome()
    {
        foreach ($this->subcontractors as $subcontractor) {
            $subcontractor->build();
        }
    }
}

interface Subcontractor
{
    public function build();
}

class FoundationSubcontractor implements Subcontractor
{
    public function build()
    {
        // Build the foundation of the home
        echo "Building the foundation\n";
    }
}

class WallsSubcontractor implements Subcontractor
{
    public function build()
    {
        // Build the walls of the home
        echo "Building the walls\n";
    }
}

class RoofSubcontractor implements Subcontractor
{
    public function build()
    {
        // Build the roof of the home
        echo "Building the roof\n";
    }
}

$builder = new HomeBuilder();
$builder->addSubcontractor(new FoundationSubcontractor());
$builder->addSubcontractor(new WallsSubcontractor());
$builder->addSubcontractor(new RoofSubcontractor());
$builder->buildHome();

In this example, the HomeBuilder class is responsible for overseeing the construction process, and the FoundationSubcontractor, WallsSubcontractor, and RoofSubcontractor classes are responsible for building different parts of the home. The buildHome method iterates through the subcontractors and calls the build method on each one, causing them to build their respective parts of the home.

The client (in this case, the home builder) can customize the construction process by adding different subcontractors to the list. This allows for greater control over the construction process and the ability to create a customized home.

Example 2

Imagine you are building a custom car. Building a car is complex and involves assembling various parts, such as the engine, transmission, and body.

Here's some example code that represents this scenario:

 

class CarBuilder
{
    private $mechanics;
 
    public function __construct()
    {
        $this->mechanics = [];
    }
 
    public function addMechanic(Mechanic $mechanic)
    {
        $this->mechanics[] = $mechanic;
    }
 
    public function buildCar()
    {
        foreach ($this->mechanics as $mechanic) {
            $mechanic->assemble();
        }
    }
}

class Mechanic
{
    public function assemble()
    {
        // Assemble a part of the car
    }
}

class EngineMechanic extends Mechanic
{
    public function assemble()
    {
        // Assemble the engine of the car
        echo "Assembling the engine\n";
    }
}

class TransmissionMechanic extends Mechanic
{
    public function assemble()
    {
        // Assemble the transmission of the car
        echo "Assembling the transmission\n";
    }
}

$builder = new CarBuilder();
$builder->addMechanic(new EngineMechanic());
$builder->addMechanic(new TransmissionMechanic());
$builder->buildCar();

 

In this example, the CarBuilder Class acts as the director in the Builder pattern. It has a list of mechanics (builders) who are responsible for assembling different parts of the car. The buildCar the method iterates through the mechanics and calls the assemble method on each one, causing them to assemble their respective parts of the car.

The Mechanic class is an abstract class that represents the interface that all mechanics must implement. The EngineMechanic and TransmissionMechanic classes are concrete implementations of the Mechanic class, each responsible for assembling a different part of the car.

The client (in this case, the car builder) can customize the construction process by adding different mechanics to the list. This allows for greater control over the construction process and the ability to create a customized car.