Design Pattern: Abstract Factory Pattern in PHP

Abstract factory pattern is used when we need multiple factories which produce related but different sets of objects. This pattern is generally used in relatively larger applications that deal with lots of classes of related classes but can be divided into multiple groups based on some criteria.

As Abstract factory pattern is a factory of the Factory pattern, so before learning the details of the Abstract factory pattern make sure to have a clear idea about Factory pattern.

This article discusses the Abstract Factory pattern implementations in PHP. Check the implementation details and examples.

Implementation

Use the following steps for the implementation-

  • Create interface for the item/product classes.
  • Create item/product classes and implement the item interface.
  • Create an abstract factory. This can be an interface or abstract class. This has the declaration of method which are responsible for generating item/product objects.
  • Create factory classes and implement the abstract factory interface/class. These classes contain method for generating item/product objects.
  • Create a factory producer class. This class is responsible for generating a factory object and returning that.

Here is a simple Abstract factory implementation in PHP. This is not any specific example, just demo/sample code.

<?php
// Abstract factory implementation in PHP

// Item interface
interface ItemInterface {
    function operation1(): void;
    function operation2(): void;
}

// Item of type 1
class Type1Item1 implements ItemInterface {
    public function operation1(): void {
        echo "Type 1 Item 1: executing operation 1n";
    }

    public function operation2(): void {
        echo "Type 1 Item 1: executing operation 2n";
    }
}

// Item of type 1
class Type1Item2 implements ItemInterface {
    public function operation1(): void {
        echo "Type 1 Item 2: executing operation 1n";
    }

    public function operation2(): void {
        echo "Type 1 Item 2: executing operation 2n";
    }
}

// Item of type 2
class Type2Item1 implements ItemInterface {
    public function operation1(): void {
        echo "Type 2 Item 1: executing operation 1n";
    }

    public function operation2(): void {
        echo "Type 2 Item 1: executing operation 2n";
    }
}

// Item of type 2
class Type2Item2 implements ItemInterface {
    public function operation1(): void {
        echo "Type 2 Item 2: executing operation 1n";
    }

    public function operation2(): void {
        echo "Type 2 Item 2: executing operation 2n";
    }
}

// Factory interface
interface FactoryInterface {
    function getItem(string $type): ?ItemInterface;
}

// Type 1 factory
class Type1Factory implements FactoryInterface {
    public function getItem(string $itemIdentifier): ?ItemInterface {
        switch (strtolower($itemIdentifier)) {
            case "item1": return new Type1Item1();
            case "item2": return new Type1Item2();
        }

        return null;
    }
}

// Type 2 factory
class Type2Factory implements FactoryInterface {
    public function getItem(string $itemIdentifier): ?ItemInterface {
        switch (strtolower($itemIdentifier)) {
            case "item1": return new Type2Item1();
            case "item2": return new Type2Item2();
        }

        return null;
    }
}

// Factory producer - Factory of Factory
class FactoryProducer {
    public static function getFactory(int $type): ?FactoryInterface {
        switch ($type) {
            case 1: return new Type1Factory();
            case 2: return new Type2Factory();
        }

        return null;
    }
}

// Demo
$factory1 = FactoryProducer::getFactory(1);

$item1 = $factory1->getItem("item1");
$item1->operation1();
$item1->operation2();

$factory2 = FactoryProducer::getFactory(2);

$item2 = $factory2->getItem("item1");
$item2->operation1();

$item3 = $factory2->getItem("item2");
$item3->operation1();
$item3->operation2();

Above code will generate the following output:

Type 1 Item 1: executing operation 1
Type 1 Item 1: executing operation 2

Type 2 Item 1: executing operation 1

Type 2 Item 2: executing operation 1
Type 2 Item 2: executing operation 2

Examples

Let’s look at a few examples of Abstract factory pattern implementation in PHP.

Example #1: Transport

Here we have 2 types of transport – two and four wheelers. We want some factory mechanism for generating transport objects.

As the object generation process of different types of transports can be different, so we want to use separate factories for different types of objects.

Transport Interface [Item Interface]

  • Create file “Transport.php”.
  • Define interface “Transport” and declare required methods.
<?php
// Transport.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;

interface Transport {
    public function start(): void;
    public function stop(): void;
    public function repair(): void;
}

Bicycle Class [Item Class]

  • Create file “Bicycle.php”.
  • Create class “Bicycle”.
  • Implement the “Transport” interface for the class. Define methods that are declared in the interface.
<?php
// Bicycle.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;


class Bicycle implements Transport {
    public function start(): void {
        echo "Bicycle Startedn";
    }

    public function stop(): void {
        echo "Bicycle Stoppedn";
    }

    public function repair(): void {
        echo "Bicycle Repairn";
    }
}

Motorcycle Class [Item Class]

  • Create file “Motorcycle.php”.
  • Create “Motorcycle” class and implement “Transport” interface.
<?php
// Motorcycle.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;

class Motorcycle implements Transport {
    public function start(): void {
        echo "Motorcycle Startedn";
    }

    public function stop(): void {
        echo "Motorcycle Stoppedn";
    }

    public function repair(): void {
        echo "Motorcycle Repairn";
    }
}

Car Class [Item Class]

  • Create a file “Car.php”.
  • Define “Car” class and implement the “Transport” interface.
<?php
// Car.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;

class Car implements Transport {
    public function start(): void {
        echo "Car Startedn";
    }

    public function stop(): void {
        echo "Car Stoppedn";
    }

    public function repair(): void {
        echo "Car Repairn";
    }
}

Truck Class [Item Class]

  • Create file “Truck.php”.
  • Define “Truck” class and implement the “Transport” interface.
<?php
// Truck.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;

class Truck implements Transport {
    public function start(): void {
        echo "Truck Startedn";
    }

    public function stop(): void {
        echo "Truck Stoppedn";
    }

    public function repair(): void {
        echo "Truck Repairn";
    }
}

Abstract Transport Factory Interface [Factory Interface]

  • Create a file named “AbstractTransportFactory.php”.
  • Define interface “AbstractTransportFactory”.
  • Declare method “getTransport”, this takes a “$type” param and generates a factory based on that.

This can be an abstract class, if required.

The “getTransport” method can be static, if we prefer.

<?php
// AbstractTransportFactory.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;


interface AbstractTransportFactory {
    public function getTransport(string $type): ?Transport;
}

Two-Wheel Transport Factory Class [Factory Class]

  • Create file “TwoWheelTransportFactory.php”.
  • Define the class “TwoWheelTransportFactory” and implement interface “AbstractTransportFactory” for the class.
  • In the “getTransport” method check the “$type” parameter and generate a two-wheel class(Bicycle, Motorcycle) object based on that.
<?php
// TwoWheelTransportFactory.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;

class TwoWheelTransportFactory implements AbstractTransportFactory {
    public function getTransport(string $type): ?Transport {
        if (strcasecmp($type, "bicycle") === 0) {
            return new Bicycle();
        }

        if (strcasecmp($type, "motorcycle") === 0) {
            return new Motorcycle();
        }

        return null;
    }
}

Four-Wheel Transport Factory Class [Factory Class]

  • Create file “FourWheelTransportFactory.php”.
  • Define the class “FourWheelTransportFactory” and implement the interface “AbstractTransportFactory” for the class.
  • In the “getTransport” method check the “$type” parameter and generate a two-wheel class(Car, Truck) object based on that.
  • Create a file named “four-wheel-transport-factory.ts”.
  • Define factory class “FourWheelTransportFactory”, and implement “AbstractTransportFactory” for the class.
<?php
// FourWheelTransportFactory.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;

class FourWheelTransportFactory implements AbstractTransportFactory {
    public function getTransport(string $type): ?Transport {
        if (strcasecmp($type, "car") === 0) {
            return new Car();
        }

        if (strcasecmp($type, "truck") === 0) {
            return new Truck();
        }

        return null;
    }
}

Factory Producer Class [Producer]

  • Create file “FactoryProducer.php”.
  • Define class “FactoryProducer”.
  • Create method “getFactory”. This method accepts param “$numberOfWheels”, and based on the number of wheels it generates an object of “TwoWheelTransportFactory” or “FourWheelTransportFactory”.

The Factory objects generated by this Factory producer will be used in the next steps to produce item/product objects.

<?php
// FactoryProducer.php

namespace BigBoxCodeDesignPatternAbstractFactoryTransport;

class FactoryProducer {
    public static function getFactory(int $numberOfWheels): ?AbstractTransportFactory {
        switch ($numberOfWheels) {
            case 2:
                return new TwoWheelTransportFactory();
            case 4:
                return new FourWheelTransportFactory();
        }

        return null;
    }
}

Demo

Use the “getFactory” method to generate a factory. And use that factory to generate transport objecs.

<?php
// demo.php

require __DIR__ . '/../../vendor/autoload.php';

use BigBoxCodeDesignPatternAbstractFactoryTransportFactoryProducer;

$transportFactory1 = FactoryProducer::getFactory(2);
$transport1 = $transportFactory1?->getTransport("bicycle");

$transport1?->start();

$transportFactory2 = FactoryProducer::getFactory(4);
$transport2 = $transportFactory2?->getTransport("truck");

$transport2?->start();

Output

Output of the code will be as below-

Bicycle Started
Truck Started

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Abstract Factory pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.