PHP Abstract Factory Design Pattern Порождающий паттерн

Абстрактная фабрика в PHP

Короткий скринкаст: семейство продуктов и фабрик строится на общих интерфейсах — это паттерн «Абстрактная фабрика» (Abstract Factory).

Abstract Factory Pattern — открыть страницу урока

Описание

В этом скринкасте мы строим паттерн на интерфейсах. ProductInterface описывает продукт, FactoryInterface — фабрику. Конкретные фабрики LaptopFactory и SmartphoneFactory создают соответствующие продукты, а клиентский код (demo.php) работает только с абстракциями — можно подменить одну «семью» объектов другой, не меняя вызывающий код.

UML-диаграмма

classDiagram class ProductInterface { <<interface>> +getInfo() string } class FactoryInterface { <<interface>> +createProduct() ProductInterface } class Laptop { -string name +__construct(name: string) +getInfo() string } class Smartphone { -string model +__construct(model: string) +getInfo() string } class LaptopFactory { +createProduct() ProductInterface } class SmartphoneFactory { +createProduct() ProductInterface } Laptop ..|> ProductInterface Smartphone ..|> ProductInterface LaptopFactory ..|> FactoryInterface SmartphoneFactory ..|> FactoryInterface LaptopFactory ..> Laptop : creates SmartphoneFactory ..> Smartphone : creates FactoryInterface --> ProductInterface : returns

Код

ProductInterface.php

interface ProductInterface
{
    public function getInfo(): string;
}

Laptop.php

class Laptop implements ProductInterface
{
    public function __construct(
        private string $name
    ) {}

    public function getInfo(): string
    {
        return 'Laptop: ' . $this->name;
    }
}

Smartphone.php

class Smartphone implements ProductInterface
{
    public function __construct(
        private string $model
    ) {}

    public function getInfo(): string
    {
        return 'Smartphone: ' . $this->model;
    }
}

FactoryInterface.php

interface FactoryInterface
{
    public function createProduct(): ProductInterface;
}

LaptopFactory.php

class LaptopFactory implements FactoryInterface
{
    public function createProduct(): ProductInterface
    {
        return new Laptop('MacBook Pro');
    }
}

demo.php

require_once 'ProductInterface.php';
require_once 'Laptop.php';
require_once 'FactoryInterface.php';
require_once 'LaptopFactory.php';

$factory = new LaptopFactory();
$product = $factory->createProduct();

echo $product->getInfo();

Заметка: почему интерфейсы

Клиент в demo.php не знает про Laptop и LaptopFactory — только про ProductInterface и FactoryInterface. Это и есть суть паттерна: код зависит от абстракций, а какую «семью» объектов собрать, решает конкретная фабрика. Добавить SmartphoneFactory — и клиент соберёт смартфон без изменения вызывающего кода.

Заметка: почему интерфейс, а не абстрактный класс

В PHP на класс приходится только одно наследование, а интерфейсов можно реализовать сколько угодно. В абстрактной фабрике члены одной «семьи» обычно не имеют общей реализации — их объединяет только контракт, поэтому подходит именно интерфейс:

abstract class AbstractProduct
{
    abstract public function getInfo(): string;
}

Такая абстракция сразу «съедает» единственное наследование: Laptop не сможет одновременно унаследовать, скажем, базовый класс модели вашего фреймворка. Плюс абстрактный класс смешивает контракт и реализацию — стоит положить туда общий метод, и все продукты семьи «втянут» его даже без необходимости, а подменить семью станет сложнее. Интерфейс задаёт только тип и поведение, оставляя реализацию каждому продукту.

Пример результата

После php demo.php в терминале появится:

Laptop: MacBook Pro

Преимущества

  • Позволяет работать с целым семейством согласованных продуктов.
  • Клиент не зависит от конкретных классов — только от абстрактных интерфейсов.
  • Замена семейства (например, вендора) не затрагивает клиентский код.
  • Гарантирует совместимость продуктов, созданных вместе.

Когда использовать

  • Когда система должна быть независима от того, как создаются её продукты.
  • Когда продуктов несколько и они образуют согласованные семейства.
  • Когда нужно переключать целые наборы продуктов во время выполнения.
  • Когда важно, чтобы продукты одного семейства использовались вместе.

Использование в Laravel

В Laravel абстрактная фабрика — это менеджеры драйверов: Illuminate\Cache\CacheManager, Illuminate\Filesystem\FilesystemManager, Illuminate\Queue\QueueManager. Каждый создаёт не один объект, а согласованное семейство реализаций (стор кэша, диск или очередь) по имени драйвера из конфигурации. Через Cache::store('redis') или Storage::disk('s3') клиент получает нужное семейство, не зная конкретных классов.