Чем паттерн «Фабричный метод» отличается от «Абстрактной фабрики»?

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

Ответ

Оба паттерна относятся к порождающим и инкапсулируют создание объектов, но решают разные задачи.

Фабричный метод (Factory Method)

Цель: Делегировать создание одного конкретного продукта подклассам. Определяет интерфейс для создания объекта, но позволяет подклассам изменять тип создаваемого объекта.

Аналогия: Компания по производству мебели имеет общий цех (Creator), но в разных филиалах (ConcreteCreator) решают, какой конкретно стул (Product) производить: офисный или кухонный.

Пример на PHP (Логирование):

// Продукт
interface Logger {
    public function log(string $message): void;
}

class FileLogger implements Logger {
    public function log(string $message): void {
        file_put_contents('app.log', $message, FILE_APPEND);
    }
}

class DatabaseLogger implements Logger {
    public function log(string $message): void {
        // Логика сохранения в БД
        echo "Log to DB: $message";
    }
}

// Создатель с фабричным методом
abstract class LoggerCreator {
    // ФАБРИЧНЫЙ МЕТОД — абстрактный, реализация у наследников
    abstract public function createLogger(): Logger;

    public function logMessage(string $message): void {
        $logger = $this->createLogger(); // Используем фабричный метод
        $logger->log($message);
    }
}

// Конкретные создатели
class FileLoggerCreator extends LoggerCreator {
    public function createLogger(): Logger {
        return new FileLogger();
    }
}

class DatabaseLoggerCreator extends LoggerCreator {
    public function createLogger(): Logger {
        return new DatabaseLogger();
    }
}

// Использование
$creator = new FileLoggerCreator();
$creator->logMessage('Test message'); // Будет записано в файл

Абстрактная фабрика (Abstract Factory)

Цель: Создание семейств взаимосвязанных или взаимозависимых продуктов (например, UI-элементов одной ОС). Гарантирует совместимость продуктов.

Аналогия: Компания производит полные гарнитуры мебели (AbstractFactory): в викторианском стиле (VictorianFactory) — стул, стол, диван одного стиля; в современном (ModernFactory) — другой набор.

Пример на PHP (UI-виджеты):

// Абстрактные продукты
interface Button { public function render(): string; }
interface Checkbox { public function render(): string; }

// Конкретные продукты для Windows
class WinButton implements Button {
    public function render(): string { return "<button>Windows Button</button>"; }
}
class WinCheckbox implements Checkbox {
    public function render(): string { return "<checkbox>Windows Checkbox</checkbox>"; }
}

// Конкретные продукты для MacOS
class MacButton implements Button {
    public function render(): string { return "<button>MacOS Button</button>"; }
}
class MacCheckbox implements Checkbox {
    public function render(): string { return "<checkbox>MacOS Checkbox</checkbox>"; }
}

// АБСТРАКТНАЯ ФАБРИКА — создаёт семейство продуктов
interface GUIFactory {
    public function createButton(): Button;
    public function createCheckbox(): Checkbox;
}

// Конкретные фабрики
class WinFactory implements GUIFactory {
    public function createButton(): Button { return new WinButton(); }
    public function createCheckbox(): Checkbox { return new WinCheckbox(); }
}

class MacFactory implements GUIFactory {
    public function createButton(): Button { return new MacButton(); }
    public function createCheckbox(): Checkbox { return new MacCheckbox(); }
}

// Клиентский код, работающий с абстрактной фабрикой
function renderUI(GUIFactory $factory): void {
    $button = $factory->createButton();
    $checkbox = $factory->createCheckbox();
    echo $button->render() . ' ' . $checkbox->render();
}

// Все элементы будут в одном стиле
renderUI(new WinFactory()); // <button>Windows Button</button> <checkbox>Windows Checkbox</checkbox>
renderUI(new MacFactory()); // <button>MacOS Button</button> <checkbox>MacOS Checkbox</checkbox>

Итоговое отличие:

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