Для чего используется паттерн «Фабрика»?

«Для чего используется паттерн «Фабрика»?» — вопрос из категории Паттерны, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Паттерн "Фабрика" (Factory Method) используется для инкапсуляции и делегирования логики создания объектов. Вместо прямого вызова конструктора с оператором new, клиентский код обращается к фабричному методу, который возвращает нужный экземпляр объекта.

Основные цели:

  • Снижение связанности: Клиентский код зависит от абстракции (интерфейса/абстрактного класса), а не от конкретных классов создаваемых объектов.
  • Централизация и упрощение создания: Вся сложная логика инициализации (выбор конкретного класса, конфигурация) сосредоточена в одном месте.
  • Упрощение расширения: Для добавления нового типа продукта нужно изменить только код фабрики, а не все места в коде, где создаются объекты.

Пример на PHP:

// Абстракция продукта
interface Report {
    public function generate(): string;
}

// Конкретные продукты
class PdfReport implements Report {
    public function generate(): string {
        return 'PDF report content';
    }
}

class CsvReport implements Report {
    public function generate(): string {
        return 'CSV report content';
    }
}

// Создатель с фабричным методом
abstract class ReportCreator {
    // Фабричный метод
    abstract public function createReport(): Report;

    public function renderReport(): string {
        $report = $this->createReport(); // Создание делегируется подклассам
        return $report->generate();
    }
}

// Конкретные создатели
class PdfReportCreator extends ReportCreator {
    public function createReport(): Report {
        // Здесь может быть сложная логика инициализации PdfReport
        return new PdfReport();
    }
}

class CsvReportCreator extends ReportCreator {
    public function createReport(): Report {
        return new CsvReport();
    }
}

// Использование
$creator = new PdfReportCreator();
echo $creator->renderReport(); // Создаст и использует PdfReport

Таким образом, паттерн позволяет подклассам решать, объект какого конкретного класса создавать.