Skip to content
Home » Use the Abstract Factory Pattern | PHP Code Examples in 2023

Use the Abstract Factory Pattern | PHP Code Examples in 2023

Using the Abstract Factory Pattern in PHP

The Abstract Factory Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. The pattern encapsulates the creation of objects within a factory object, which is responsible for creating the appropriate objects based on the parameters passed to it.

The Abstract Factory Pattern is useful in situations where there is a need to create families of related objects that work together seamlessly, but the specific types of objects to be created are not known until runtime. 

Using an abstract factory to create the objects, the client code can be decoupled from the concrete classes that implement the objects, allowing for greater flexibility and extensibility of the software system.

Article Highlights

  • The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
  • Benefit – The abstract factory ensures that all objects within a family are created consistently, adhering to the same set of rules and guidelines.
  • Con – Can be overkill for small projects

Abstract Factory Design Pattern PHP Code Example

<?php

interface Button {

    function setClick($fn);
    function setLabel($label);
}

interface Spinner {

    function setDuration($ms);
}

interface TextView {

    function maxPad($unit);
}

class ClassicButtonV1 implements Button {

    private $label;
    private $clickEvent;

    function setClick($fn) {
        $this->clickEvent = $fn;
    }

    function setLabel($label) {
        $this->label = $label;
    }

}

class ClassicButtonV2 implements Button {

    private $label;
    private $clickEvent;

    function setClick($fn) {
        $this->clickEvent = $fn;
    }

    function setLabel($label) {
        $this->label = $label;
    }

}

class ClassicSpinnerV1 implements Spinner {

    private $ms;

    function setDuration($ms) {
        $this->ms = $ms;
    }
}

class ClassicSpinnerV2 implements Spinner {

    private $ms;

    function setDuration($ms) {
        $this->ms = $ms;
    }
}

class ClassicTextViewV1 implements TextView {

    private $unit;

    function maxPad($unit) {
        $this->unit = $unit;
    }
}

class ClassicTextViewV2 implements TextView {

    private $unit;

    function maxPad($unit) {
        $this->unit = $unit;
    }
}

interface UI {

    function setButton($button);
    function setSpinner($spinner);
    function setTextView($textView);
}

class ClassicUIV1 implements UI {

    private $button;
    private $spinner;
    private $textView;

    public function setButton($button) {
        $this->button = $button;
    }

    public function setSpinner($spinner) {
        $this->spinner = $spinner;
    }

    public function setTextView($textView) {
        $this->textView = $textView;
    }

}

class ClassicUIV2 implements UI {

    private $button;
    private $spinner;
    private $textView;

    public function setButton($button) {
        $this->button = $button;
    }

    public function setSpinner($spinner) {
        $this->spinner = $spinner;
    }

    public function setTextView($textView) {
        $this->textView = $textView;
    }

}

interface UIElementsFactory {
    function createButton();
    function createSpinner();
    function createTextView();
}

class ClassicUIElementsV1Factory implements UIElementsFactory {

    function createButton() {
        return new ClassicButtonV1();
    }

    function createSpinner() {
        return new ClassicSpinnerV1();
    }

    function createTextView() {
        return new ClassicTextViewV1();
    }
}

class ClassicUIElementsV2Factory implements UIElementsFactory {

    function createButton() {
        return new ClassicButtonV2();
    }

    function createSpinner() {
        return new ClassicSpinnerV2();
    }

    function createTextView() {
        return new ClassicTextViewV2();
    }
}

interface UIFactory {

    function createUI(); 
}

class ClassicUIV1Factory implements UIFactory {

    private $factory; //UI Elements Factory

    function __construct() {
        $this->factory = new ClassicUIElementsV1Factory();
    }

    function createUI()
    {

        //Use these UI elements to create an entire UI
        $button = $this->factory->createButton();
        $spinner = $this->factory->createSpinner();
        $textView = $this->factory->createTextView();
    
        $classicUIV1 = new ClassicUIV1();

        $classicUIV1->setButton($button);
        $classicUIV1->setSpinner($spinner);
        $classicUIV1->setTextView($textView);

        return $classicUIV1;
    }
}

class ClassicUIV2Factory implements UIFactory {

    private $factory; //UI Elements Factory

    function __construct() {
        $this->factory = new ClassicUIElementsV2Factory();
    }

    function createUI()
    {

        //Use these UI elements to create an entire UI
        $button = $this->factory->createButton();
        $spinner = $this->factory->createSpinner();
        $textView = $this->factory->createTextView();
    
        $classicUIV2 = new ClassicUIV2();

        $classicUIV2->setButton($button);
        $classicUIV2->setSpinner($spinner);
        $classicUIV2->setTextView($textView);

        return $classicUIV2;
    }
}

function main() {

    $classicUIV1Factory = new ClassicUIV1Factory();

    $classicUIV2 = $classicUIV1Factory->createUI();
}


?>
Abstract Factory Pattern PHP

Table of Contents

What is the Abstract Factory Pattern

The Abstract Factory Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. The pattern encapsulates the creation of objects within a factory object, which is responsible for creating the appropriate objects based on the parameters passed to it.

Abstract Factory Pattern PHP

Abstract Factory Pattern Example

Let’s assume an application where users can switch between different UIs. Currently, it has only one UI variant: Classic 1.0. UI is composed of elements: Button, Spinner & TextView. In other words, a family of UI elements makes an entire UI.

Using the factory pattern, we can decouple application code from UI creation by delegating it to a factory class.

factory php

Let’s look at the pseudocode of a concrete UI factory class and understand how it assembles the UI.

<?php


interface UIFactory {


    function createUI();
    function createButton();
    function createSpinner();
    function createTextView();
}


class ClassicUIFactory implements UIFactory {


    function createUI()
    {
        //Use these UI elements to create an entire UI
        $button = $this->createButton();
        $spinner = $this->createSpinner();
        $textview = $this->createTextView();
       
        return "Classic UI";
    }


    function createButton() {
        return "Classic Button v1";
    }


    function createSpinner() {
        return "Classic Spinner v1";
    }


    function createTextView() {
        return "Classic TextView v1";
    }


}


?>

There’s no problem in such an implementation as long as the family of UI elements don’t change at all. What do we mean by that?

Suppose we introduce classic UI 2.0 with different UI elements from the class UI 1.0. Both the classic UIs are supposed to use the ClassicUIFactory

ui-family

The ClassicUIFactory returns a family of UI elements for classic UI 1.0, and that family is different from that of classic UI 2.0. That’s the problem. Either we have to parameterise the factory methods or create separate factories.

The solution is yet to come, but let’s first look at the problems from a design perspective.

Problem 🙁

Single Responsibility principle

“A class should have one and only one responsibility.”, states the single responsibility principle. The idea behind the factory pattern was to delegate object creation in a separate class so the other classes could focus on their functions.

Now there’s a similar problem in the factory class itself. The UIFactory was supposed to return a UI element without knowing the family UI elements. Currently, the factory couples to concrete instances of UI elements. 

So, the factory class is additionally responsible for wiring the right UI elements to create an overall UI. Ideally, it should delegate this responsibility to another factory class.

Open-closed principle

“A class should be closed for modification but open for extension.”, states the open/closed principle. The UI elements are prone to change with different versions of a UI. For instance – we can add Classic UI 3.0 with an entirely different family of UI elements.

The current factory class may use a parameter to decide which UI element to return. In the face of a change, we will have no other option but to open up the existing factory classes and make changes right there, violating this principle.

Compatible products

In our case, we have a set of related products or a family of products – namely, the UI elements. It is important to use UI elements from the same family that are always compatible. Any mishap in this process is a result of erroneous code. 

For instance, we don’t want to use a class button in a classic UI 1.0 when it is only designed for classic UI 2.0. This problem may happen because they are closely related families – both represent classic UI.

So, how do we make sure to address these problems? How about parameterising the factory methods? Certainly, it is an option, but we can do better.

Solution 🙂

Encapsulate the change

“Encapsulate what varies” is a golden rule for flexible designs. In our case,  the variance happens in the family of UI elements. Why do we have factory classes in the first place? It’s because we want to encapsulate the object creation. After all, objects are the most variable aspect of our program – we can add or remove objects and certainly don’t want to affect the entire software.

Now we have another set of objects closely related, forming an entire product. The set or family of objects vary as we add more families to support variations in our program. So, a viable solution is encapsulating this change.

Introducing UI elements factory

Just as we did in the factory pattern, we will add factories to create families of UI elements. 

Abstract Factory Pattern PHP

Here’s a pseudocode for these factories.

<?php


interface UIElementsFactory {
    function createButton();
    function createSpinner();
    function createTextView();
}


class ClassicUIElementsV1Factory implements UIElementsFactory {


    function createButton() {
        return "Classic Button v1";
    }


    function createSpinner() {
        return "Classic Spinner v1";
    }


    function createTextView() {
        return "Classic Text View v1";
    }
}


class ClassicUIElementsV2Factory implements UIElementsFactory {


    function createButton() {
        return "Classic Button v2";
    }


    function createSpinner() {
        return "Classic Spinner v2";
    }


    function createTextView() {
        return "Classic Text View v2";
    }
}
?>

These factories work similarly to others except that they have UIFactory as a client. Let’s understand how these two factories work together.

Factories use factories

UIFactory uses UIElementFactory to create the right instances of UI elements. Though both these are interfaces but using polymorphism, they can map to the right entities. Let’s also remind ourselves of another good old principle, “program to interface not implementation”.

ui-factories

Let’s now understand how the two factories work together through pseudocode.

interface UIFactory {


    function createUI();
}


class ClassicUIV1Factory implements UIFactory {


    private $factory; //UI Elements Factory


    function __construct($factory) {
        $this->factory = new ClassicUIElementsV1Factory();
    }


    function createUI()
    {


        //Use these UI elements to create an entire UI
        $button = $this->factory->createButton();
        $spinner = $this->factory->createSpinner();
        $textview = $this->factory->createTextView();
   
        return "Classic UI";
    }
}


class ClassicUIV2Factory implements UIFactory {


    private $factory; //UI Elements Factory


    function __construct() {
        $this->factory = new ClassicUIElementsV2Factory();
    }


    function createUI()
    {


        //Use these UI elements to create an entire UI
        $button = $this->factory->createButton();
        $spinner = $this->factory->createSpinner();
        $textview = $this->factory->createTextView();
   
        return "Classic UI";
    }
}

The UIFactory now rely on the UIElementsFactory for creating the right set of objects. The former is relieved from additional responsibilities for creating a family of related objects. 

View complete pseudocode.

Benefits of the Abstract Factory Pattern

  1. Encapsulation of object creation logic: The abstract factory encapsulates the creation of objects within a single class, providing a clear separation between the client code and the object creation logic.
  1. Flexibility and extensibility: Using the abstract factory pattern makes it easier to add new variants of products to the system without modifying the existing code. The pattern allows for the creation of families of related objects that can be easily extended with new variations.
  1. Consistency of objects: The abstract factory ensures that all objects within a family are created consistently, adhering to the same set of rules and guidelines. This helps to ensure that the objects are compatible with one another and can work together seamlessly.
  1. Loose coupling: The abstract factory pattern promotes loose coupling between the client code and the concrete classes that implement the objects. This makes it easier to replace or modify the implementation of the objects without affecting the client code.

Complete Architecture | Abstract Factory Pattern in PHP

Abstract Factory Pattern PHP

Abstract Factory Pattern PHP Pseudocode Example

<?php

interface Button {

    function setClick($fn);
    function setLabel($label);
}

interface Spinner {

    function setDuration($ms);
}

interface TextView {

    function maxPad($unit);
}

class ClassicButtonV1 implements Button {

    private $label;
    private $clickEvent;

    function setClick($fn) {
        $this->clickEvent = $fn;
    }

    function setLabel($label) {
        $this->label = $label;
    }

}

class ClassicButtonV2 implements Button {

    private $label;
    private $clickEvent;

    function setClick($fn) {
        $this->clickEvent = $fn;
    }

    function setLabel($label) {
        $this->label = $label;
    }

}

class ClassicSpinnerV1 implements Spinner {

    private $ms;

    function setDuration($ms) {
        $this->ms = $ms;
    }
}

class ClassicSpinnerV2 implements Spinner {

    private $ms;

    function setDuration($ms) {
        $this->ms = $ms;
    }
}

class ClassicTextViewV1 implements TextView {

    private $unit;

    function maxPad($unit) {
        $this->unit = $unit;
    }
}

class ClassicTextViewV2 implements TextView {

    private $unit;

    function maxPad($unit) {
        $this->unit = $unit;
    }
}

interface UI {

    function setButton($button);
    function setSpinner($spinner);
    function setTextView($textView);
}

class ClassicUIV1 implements UI {

    private $button;
    private $spinner;
    private $textView;

    public function setButton($button) {
        $this->button = $button;
    }

    public function setSpinner($spinner) {
        $this->spinner = $spinner;
    }

    public function setTextView($textView) {
        $this->textView = $textView;
    }

}

class ClassicUIV2 implements UI {

    private $button;
    private $spinner;
    private $textView;

    public function setButton($button) {
        $this->button = $button;
    }

    public function setSpinner($spinner) {
        $this->spinner = $spinner;
    }

    public function setTextView($textView) {
        $this->textView = $textView;
    }

}

interface UIElementsFactory {
    function createButton();
    function createSpinner();
    function createTextView();
}

class ClassicUIElementsV1Factory implements UIElementsFactory {

    function createButton() {
        return new ClassicButtonV1();
    }

    function createSpinner() {
        return new ClassicSpinnerV1();
    }

    function createTextView() {
        return new ClassicTextViewV1();
    }
}

class ClassicUIElementsV2Factory implements UIElementsFactory {

    function createButton() {
        return new ClassicButtonV2();
    }

    function createSpinner() {
        return new ClassicSpinnerV2();
    }

    function createTextView() {
        return new ClassicTextViewV2();
    }
}

interface UIFactory {

    function createUI(); 
}

class ClassicUIV1Factory implements UIFactory {

    private $factory; //UI Elements Factory

    function __construct() {
        $this->factory = new ClassicUIElementsV1Factory();
    }

    function createUI()
    {

        //Use these UI elements to create an entire UI
        $button = $this->factory->createButton();
        $spinner = $this->factory->createSpinner();
        $textView = $this->factory->createTextView();
    
        $classicUIV1 = new ClassicUIV1();

        $classicUIV1->setButton($button);
        $classicUIV1->setSpinner($spinner);
        $classicUIV1->setTextView($textView);

        return $classicUIV1;
    }
}

class ClassicUIV2Factory implements UIFactory {

    private $factory; //UI Elements Factory

    function __construct() {
        $this->factory = new ClassicUIElementsV2Factory();
    }

    function createUI()
    {

        //Use these UI elements to create an entire UI
        $button = $this->factory->createButton();
        $spinner = $this->factory->createSpinner();
        $textView = $this->factory->createTextView();
    
        $classicUIV2 = new ClassicUIV2();

        $classicUIV2->setButton($button);
        $classicUIV2->setSpinner($spinner);
        $classicUIV2->setTextView($textView);

        return $classicUIV2;
    }
}

function main() {

    $classicUIV1Factory = new ClassicUIV1Factory();

    $classicUIV2 = $classicUIV1Factory->createUI();
}

?>

Pros and Cons of the Abstract Factory Pattern in PHP

ProsCons
Encapsulates object creation logicCan be overkill for small projects
Flexibility and extensibilityAdds complexity to the code
Consistency of objectsCan lead to a large number of classes
Loose couplingCan be difficult to understand for developers unfamiliar with the pattern
Supports the Open/Closed principleMay require additional testing and debugging
Supports the Single Responsibility principle
Promotes modular design

Where is the Abstract Factory Pattern Used

  1. Graphical user interface (GUI) frameworks: GUI frameworks often require the creation of multiple objects that need to work together seamlessly, such as buttons, text boxes, and menus. 
  1. Database access libraries: Database access libraries may need to create different types of database connections and commands depending on the type of database being used..
  1. Operating system APIs: Operating system APIs may need to create different types of objects depending on the platform being used.
  1. Games and simulations: Games and simulations often require the creation of multiple objects that need to work together seamlessly, such as characters, weapons, and environments.
  1. eCommerce platforms: eCommerce platforms may need to create different types of payment gateways and shipping methods depending on the needs of the customers. 

What is the Abstract Factory Pattern

The Abstract Factory Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. The pattern encapsulates the creation of objects within a factory object, which is responsible for creating the appropriate objects based on the parameters passed to it.

Using the Abstract Factory Pattern in PHP Today

That’s all for the abstract factory pattern. Let’s have a quick recap. The Abstract Factory Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.

The article features an example of a UI application where users can switch between different UIs. A UI is composed of a closely related set of UI elements. Initially, we apply the factory pattern to delegate object creation to the factory class. However, the factory class now has the additional responsibility of keeping track of families of objects so that members of the same family are initialized.

Such a factory class violates design principles and that’s why we devise another approach where we can encapsulate the changing aspect of the program – the UI elements. For that reason, we create another factory that creates a family of objects.

This way the main factory classes would only be concerned with the UI type, while the newly created UI elements factory does the rest of the job by creating the right set of objects.

Using the abstract factory we create a robust, more flexible solution with the least coupling between the creator and products.

That’s all. See you in another design pattern article.

Books on Design Patterns

Want to learn more about Design Patterns? There are many great resources online. We recommend the following books for your collection as they both can teach you the theoretical and the application of using design patterns in your day-to-day programming. Feel free to use the following Amazon affiliate links if you’d like to purchase them and a way to support our efforts.

Design Patterns: Elements of Reusable Object-Oriented Software

Design Patterns: Elements of Reusable Object-Oriented Software book

This is the book that started it all. I believe that every programmer should have a referenced copy to this book at some point in their career. There have been many updates and excellent newer content through the years, but this is a classic. It still stands the test of time and is just as relevant for today as it was in the original printing in the 90s.

Check it out on amazon

Learning PHP Design Patterns

This is an excellent book to go beyond the theory and apply it to writing good PHP code. Learning PHP Design Patterns is published by the popular O’Reilly media company. O’Reilly consistently publishes some of the most useful reference material related to software development. They are known to provide materials that thoroughly cover a topic in a way that is simple to understand. I recommend this book to every PHP developer.

Check it out on amazon

Want to see our full review of books on design patterns? Read our huge review article on over 15 design pattern books.

Design Patterns in PHP Learning Series.

This article is part of our series of design patterns in PHP. We are going through all of the patterns and showing how they can help you build better applications. Browse through our full list of patterns below.