Select Page

Abstract Factory Design Pattern with Example in PHP

Abstract factory method is useful for creating products of related family. Create objects of product from sub-classes. A family could have multiple member and each member could have variation among them but they behave similarly.

For example: Let’s consider a furniture family consist of member like chair, table, sofa. Here member may have different type in looks. Suppose chair may have different types like: modern, victorian, art deco. Similarly table and sofa may have different type as well.

4 Steps for implementing Abstract Factory Design Pattern

I have divided the implementation into four easy steps:

Step 1: Create Factory Abstract Class

Factory class will produce multiple product through abstract method.

abstract class FurnitureFactory
{
    abstract public static function createChair(): ChairInterface;

    abstract public static function createTable(): TableInterface;

    abstract public static function createSofa(): SofaInterface;
}

Step 2: Create Factory Concrete Class

Factory concrete class will extends the Factory class so that it implement abstract method. Factory concrete class will implement each distinct product variation and responsible for creating object of product.


class ModernFurniture extends FurnitureFactory
{
    public static function createChair(): ChairInterface
    {
        return new ModernChair();
    }
    public static function createTable(): TableInterface
    {
        return new ModernTable();
    }
    public static function createSofa(): SofaInterface
    {
        return new ModernSofa();
    }
}

Step 3: Interface of each Distinct Product

Interface will be implemented by the product class so that each product have consistency in their behaviour. This way we don’t have to worry about the variations. Since all variations will implement same interface we can also use property and method of class same way.

interface ChairInterface
{
    public function legs(): int;

    public function sitting();
}

interface TableInterface
{
    public function legs(): int;

    public function hasDrawer(): bool;
}

interface SofaInterface
{
    public function seats(): int;
    public function hasDivan(): bool;
}

Step 4: Declare Product Concrete Class for each Product

Each product will have separate class by implementing interface.

class ModernChair implements ChairInterface
{
    public function legs(): int
    {
        return 4;
    }

    public function sitting()
    {
        return 'fine';
    }
}

class ModernTable implements TableInterface
{
    public function legs(): int
    {
        return 4;
    }

    public function hasDrawer(): bool
    {
        return true;
    }
}

class ModernSofa implements SofaInterface
{
    public function seats(): int
    {
        return 5;
    }

    public function hasDivan(): bool
    {
        return false;
    }
}

Now our product is ready to use by the client code

$modern_chair = ModernFurniture::createChair();
echo $modern_chair->legs();

From this Modern Furniture class will can create table & sofa as well and can show users as relevant product.

In future we need more variations for the furniture we can simple create another variation Factory Concrete class without touching any other code 🙂

Factory Method Design Pattern with Example in PHP

Factory Method is one of the creational design pattern. In simple words, we can say: factory method is a creational design pattern that is mainly focused on object creation in an abstract way from sub-classes. It means we will let the sub-class to create object of product concrete class.

When to use Factory Method design pattern

When we don’t know how many types of product or sub classes could be needed.

Make things loosely coupled

When we need to create object from sub-classes instead of product concrete class

Advantage of Factory Method design pattern

The Factory method design pattern makes the code loosely coupled & reuse able. This way we can follow the single responsibility and open, close principle of SOLID. Besides, we don’t need to worry about the enhancement or scalability of services.

Real Life Example in PHP

Let’s take an example of book library, suppose we run a small book library and for now we are selling Programming Books. Within a few months we got popularity and getting many request for storing Mathematic Books. In future we may have much more requests for more genres. That is really good for the business.

So here we don’t know beforehand what we may need in future. So if we write code only taking care of programming related books selling logics then we may encounter to refactor code again. Even we may need to write entire logics again for other genres. That is really bad 🙁

So let’s jump into the code and see how can solve above discussed problem:

First we will create an abstract class that will contain a factory method like below:

abstract class BookFactory
{
    abstract public function createBook($type): GenericBook;
}

This class is basically called Factory Class. Since it’s containing an abstract method so the class that will be derived from it will must implement this method & follow the signature. It means the return type of createBook method will be an interface of GenericBook.

Now let’s create a sub-class that is basically Factory Concrete Class. The class which is responsible for creating object of Product Concrete class.

class Book extends BookFactory
{
    protected $name, $author;

    public function __construct($name, $author)
    {
        $this->name = $name;
        $this->author = $author;
    }

    public function createBook($type): GenericBook
    {
        try {
            return new $type($this->name, $this->author);
        } catch (\Throwable $th) {
            throw $th;
        }
    }
}

So all is going good, we have implemented createBook method with proper signature & this is a constructor method for setting up basic things. We are creating object here on fly on the run time, beforehand we don’t know that object we really want to create but as long as it’s returning GenericBook interface all is good. Through the interface we can enforce the Product Concrete Class to implement required methods.

Let’s create the interface:

interface GenericBook
{
    public function bookName(): string;

    public function bookAuthor(): string;

    public function price();
}

Now let’s create Product Concrete Class that contains logics about particular genre books.

class ProgrammingBook implements GenericBook
{
    private $bookName, $bookAuthor;
    private $price = '$120';

    public function __construct($name, $author)
    {
        $this->bookName = $name;
        $this->bookAuthor = $author;
    }

    public function __get($name)
    {
        echo $name . ' prop is not available, try method';
    }

    public function bookName(): string
    {
        return $this->bookName;
    }

    public function bookAuthor(): string
    {
        return $this->bookAuthor;
    }

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

Now our code is entirely following Factory Method Design Pattern and is loosely coupled. Below way client will use the class:

$book = new Book('PHP Book', 'Rasmus Lerdorf');
$programmingBook = $book->createBook('ProgrammingBook');
echo $programmingBook->bookName() . '<br>';
echo $programmingBook->bookAuthor() . '<br>';
echo $programmingBook->price() . '<br>';

This way client may create as many programming book as they need.

Now If we need more genre books then simple we can create another class and implement all logics to that particular class and don’t need to touch anything else. Even we can take advantage of common things that already have on the ProgrammingBook class.

Here is how to achieve it:

class MathBook extends ProgrammingBook
{
    private $price = '$90';

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

Supposed we need to sell Math books & we have all things same as programming book but price is different, so we can simple create a class for MathBook and extends ProgrammingBook. Since price is different we can override from particular class, that is really cool 😀

That’s all for the Factory Method, don’t forget to comment your recommendation/suggestion.