Builder Pattern : Crafting complex objects piece by piece

The Builder Pattern is a creational design pattern that facilitates the construction of complex objects step by step. This pattern is particularly beneficial when an object needs to be configured with numerous options.

Decoding the Jargon: A Simple Analogy

To demystify technical jargon, let's use a relatable analogy: building a sandwich at Subway. You don't just order "a sandwich." Instead, you select each component — from bread to fillings — based on your preferences, akin to constructing an object piece by piece in the Builder Pattern.

A Practical Illustration

Consider working for a property technology company like Airbnb or Booking.com. You're tasked with managing property listings, which are initially handled procedurally:

$exampleStudentProperty1 = new stdClass();
$exampleStudentProperty1->type = 'Apartment';
$exampleStudentProperty1->owner = 'Example Student Property 1';
$exampleStudentProperty1->rooms = 3;
$exampleStudentProperty1->hasGarage = true;
$exampleStudentProperty1->hasGarden = false;
$exampleStudentProperty1->setLocation('Manchester');

$exampleStudentProperty2 = new stdClass();
$exampleStudentProperty2->type = 'Apartment';
$exampleStudentProperty2->owner = 'Example Student property 2';
$exampleStudentProperty2->rooms = 3;
$exampleStudentProperty2->hasGarage = true;
$exampleStudentProperty2->hasGarden = false;
$exampleStudentProperty2->setLocation('Manchester');

This procedural approach is functional but lacks structure and scalability.

Embracing the Builder Pattern

The Builder Pattern allows for the incremental construction of an object, making the process more manageable and flexible. Here's how to refactor the above code using the Builder Pattern:

class PropertyBuilder
{
    protected $property;

    public function __construct()
    {
        $this->property = new stdClass();
    }

    public function setType($type)
    {
        $this->property->type = $type;
        return $this;
    }

    public function setOwner($owner)
    {
        $this->property->owner = $owner;
        return $this;
    }

    public function setRooms($rooms)
    {
        $this->property->rooms = $rooms;
        return $this;
    }

    public function setHasGarage($hasGarage)
    {
        $this->property->hasGarage = $hasGarage;
        return $this;
    }

    public function setHasGarden($hasGarden)
    {
        $this->property->hasGarden = $hasGarden;
        return $this;
    }

    public function setLocation($location)
    {
        $this->property->location = $location;
        return $this;
    }

    public function build()
    {
        return $this->property;
    }
}

// Using the Builder Pattern
$propertyBuilder = new PropertyBuilder();
$exampleStudentProperty1 = $propertyBuilder
    ->setType('Apartment')
    ->setOwner('Example Student Property 1')
    ->setRooms(3)
    ->setHasGarage(true)
    ->setHasGarden(false)
    ->setLocation('Manchester')
    ->build();

Meet the Director

The Director class orchestrates the construction process, ensuring that each step is executed in the correct order. This abstraction further simplifies object creation:

class PropertyDirector
{
    protected $builder;

    public function __construct(PropertyBuilder $builder)
    {
        $this->builder = $builder;
    }

    public function buildProperty($type, $owner, $rooms, $hasGarage, $hasGarden, $location)
    {
        return $this->builder
            ->setType($type)
            ->setOwner($owner)
            ->setRooms($rooms)
            ->setHasGarage($hasGarage)
            ->setHasGarden($hasGarden)
            ->setLocation($location)
            ->build();
    }
}

$director = new PropertyDirector(new PropertyBuilder());
$exampleStudentProperty1 = $director->buildProperty(
    type: 'Apartment',
    owner: 'Example Student Propery 1',
    rooms: 3,
    hasGarage: true,
    hasGarden: false,
    location: 'Manchester'
);

Laravel's Query Builder: A Real-world Example

Laravel's Query Builder is an excellent example of the Builder Pattern in action, allowing developers to construct database queries step by step:

$query = DB::table('properties')
    ->select('type', 'rooms', 'location')
    ->where('hasGarage', true)
    ->where('hasGarden', false)
    ->get();

Use Cases

The Builder Pattern is versatile, applicable in scenarios like dynamic form generation, API response construction, and HTML element creation, enhancing code readability and maintainability.

Conclusion

The Builder Pattern offers a structured approach to constructing complex objects, promoting clarity, flexibility, and maintainability. By adopting this pattern, developers can ensure a more efficient and adaptable codebase, ready to meet the evolving needs of their projects.