Facade and Builder design patterns in PHP

Two more design pattern examples and quick explanations guys. Yes, I know, I promise that I’ll try to post more interesting stuff (and more often) in future articles, like “10 things you should know if you want to become a great developer”. Well guess what, good knowledge of the most common design patterns is definitely one of those things (a desperate effort to be an amusing blogger).

On a more serious note, Facade and Builder patterns are two very different patterns with very different purpose of use, and I’ve seen people mixing them up quite often. Let’s try to explain them theoretically and piratically, very quickly and with short examples, and I think that you will definitely see the difference.

The Facade design pattern

The Facade design pattern is a structural design pattern that offers a clean and simple access and interface to classes with complex implementation, packages in framework or sub-modules in a module that you need to perform a complex job. Basically, if you constantly need to instantiate and call a large list of classes and methods in order to complete a single task, then you’ll probably benefit from the Facade design pattern. You can organize all those calls that you need to repeat every time you need them in a single Facade class and use the facade as a one liner. Let’s see that in a real scenario.

Let’s say that you have a company that produces multiple different products but you are also a distributor for other companies and you are selling their products too. You have a website and you are constantly updating your web-based catalog with your products, but also the products from your clients. You do not sell products through your website, but you need to share your products to various global e-commerce sites every time you create a new product in your application, you need to share the same product on your official Facebook page and you need to send an email. Lets say that for some particular reason, there are multiple places in your application where you are creating those products (from different pages or admin panels) and it is hard to maintain all these complex blocks of functionalities every time you are creating a new product. You might need to implement the Facade pattern here. Lets see how this would look, implemented in PHP:

class Product
{
    public function store($data)
    {
        // Store the product in your database
    }
}

class ExternalAppOneInteractor
{
    public function createProduct($data)
    {
        // Create the product on a third party 
        // e-commerce application through their API
    }
}

class ExternalAppTwoInteractor
{
    public function createProduct($data)
    {
        // Create the product on another third party
        // e-commerce application through their API
    }
}

class Email
{
    public function send($title, $message, $email)
    {
        // Send an email
    }
}

class FacebookInteractor
{
    public function share($data)
    {
        // Share the product on your Facebook page
    }
}



class ProductFacade
{
    protected $product;

    protected $appOneInteractor;

    protected $appTwoInteractor;

    protected $email;

    protected $fbInteractor;

    public function __construct(
        Product $product,
        ExternalAppOneInteractor $appOneInteractor,
        ExternalAppTwoInteractor $appTwoInteractor,
        Email $email,
        FacebookInteractor $fbInteractor
    ) {

    }

    public function create($productData)
    {
        // Store the product in your database
        $storedProduct = $this->product->store($productData);

        // Create the product on a third party e-commerce 
        // application through their API
        $this->appOneInteractor->createProduct($storedProduct);

        // Create the product on another third party e-commerce
        // application through their API
        $this->appTwoInteractor->createProduct($storedProduct);

        // Send an email
        $emailTitle = 'Test email title';
        $emailMessage = 'Test email message';
        $this->email->send(
            $emailTitle,
            $emailMessage,
            $storedProduct->email
        );

        // Share the product on your Facebook page
        $this->fbInteractor->share($storedProduct);

        return $storedProduct;
    }
}

$product = [
    ...
];

$productFacade = new ProductFacade(
        new Product(),
        new ExternalAppOneInteractor(),
        new ExternalAppTwoInteractor(),
        new Email(),
        new FacebookInteractor()
    );

$productFacade->create($product);

As you can see from the example above, it is pretty simple to build a single instance of the ProductFacade class and to call for a single method, every time when you will need to simultaneously execute all of the above different jobs. Just, please be aware that this is just a simple code in order to explain the nature and principles of the pattern and its implementation might be more complex in a real world example because, for example, the additional classes instantiated in the facade class, like Product, Email and all other, might have additional dependencies that need to be tackled, etc.

The Builder design pattern

The builder deign pattern is a creational design pattern that could be used in cases when we need to create complex specific class objects in a flexible way with possibilities to set properties and objects dynamically. This is very different from the Facade pattern because, the Facade pattern usually offers way more simple and static way of executing complex tasks, but without the flexibility of the client to set and configure properties and to know about them as a whole.

Lets see how this will look like with some simple code examples:

class Product
{
    public $name;

    public $description;

    public $price;

    public $sellingAs;

    public function __construct()
    {
        
    }
}

interface ProductBuilderInterface
{
    public function setName($name);
    public function setDescription($description);
    public function setPrice($price);
    public function setSellingAs($sellingAs);
    public function getProduct();
}

class ManufacturerProductBuilder implements ProductBuilderInterface
{
    private $product;

    public function __construct(Product $product)
    {
        $this->product = $product;
    }

    public function setName($name)
    {
        $this->product->name = $name;
        return $this;
    }

    public function setDescription($description)
    {
        $this->product->description = $description;
        return $this;
    }

    public function setPrice($price)
    {
        $this->product->price = $price;
        return $this;
    }

    public function setSellingAs($sellingAs)
    {
        $this->product->sellingAs = $sellingAs;
        return $this;
    }

    public function getProduct()
    {
        return $this->product;
    }
}

class DistributorProductBuilder implements ProductBuilderInterface
{
    private $product;

    public function __construct(Product $product)
    {
        $this->product = $product;
    }

    public function setName($name)
    {
        $this->product->name = $name;
        return $this;
    }

    public function setDescription($description)
    {
        $this->product->description = $description;
        return $this;
    }

    public function setPrice($price)
    {
        $this->product->price = $price;
        return $this;
    }

    public function setSellingAs($sellingAs)
    {
        $this->product->sellingAs = $sellingAs;
        return $this;
    }

    public function getProduct()
    {
        return $this->product;
    }
}

$manufacturerProductBuilder = new ManufacturerProductBuilder(new Product());
$manufacturerProduct = $manufacturerProductBuilder
    ->setName('Manufacturer Product Name')
    ->setDescription('Manufacturer Product Description')
    ->setPrice(25)
    ->setSellingAs('manufacturer')
    ->getProduct();

$distributorProductBuilder = new DistributorProductBuilder(new Product());
$distributorProduct = $distributorProductBuilder
    ->setName('Distributor Product Name')
    ->setDescription('Distributor Product Description')
    ->setPrice(32)
    ->setSellingAs('distributor')
    ->getProduct();

// NOW YOU CAN CREATE/STORE/SAVE YOUR PRODUCT

As you can clearly see from the code examples, there is no connection between the Facade and the Builder design patterns. The first is from the structural and the second from the creational group of software design patterns and it is very clear that the usage and the implementation is totally different. Maybe the names of the patterns are those who could cause misunderstanding and wrong interpretation.

Also you should be noted that there are variations of these patterns and different scenarios are requiring adaptations. For example, you have to know that the Builder pattern could be also used through a director class. Please consider the following example:

class ProductDirector
{
    public function build(
        ProductBuilderInterface $builder,
        $name,
        $description,
        $price,
        $sellingAs
    ) {
        $builder->setName($name)
            ->setDescription($description)
            ->setPrice($price)
            ->setSellingAs($sellingAs)
            ->getProduct();
    }
}

$manufacturerProductBuilder = new ProductDirector();
$manufacturerProductBuilder->build(
        new ManufacturerProductBuilder(new Product()),
        'Manufacturer Product Name',
        'Manufacturer Product Description',
        25,
        'manufacturer'
    );

$distributorProductBuilder = new ProductDirector();
$distributorProductBuilder->build(
        new DistributorProductBuilder(new Product()),
        'Distributor Product Name',
        'Distributor Product Description',
        32,
        'distributor'
    );

// NOW YOU CAN CREATE/STORE/SAVE YOUR PRODUCT

And it is very logical, as you can see from the example itself, the Builder pattern execution is slightly different in such a case.

Please keep in mind that these examples are absolutely simple examples of the pattern usage and implementation with a special note on the concepts of the patterns. I strongly believe that if you understand the concept of a pattern, it should not be very difficult for you to implement it in any programming language. Keep in mind the SOLID principles and do not forget that type hints and return types are your best friend in complex solutions. The examples are written without usage of type hints in order to simplify the code readability and pay attention to the concepts.