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

Ответ

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

Фабричный метод (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>

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

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

Ответ 18+ 🔞

Давай разжую тебе эту тему про фабрики, а то я вижу, у тебя в глазах уже квадратные скобки плывут. Слушай сюда, это как сравнивать поход в столовую за одним конкретным борщом и заказ комплексного обеда, где всё на одной тарелке и сочетается.

Фабричный метод — это как заказать одно блюдо, но в разных забегаловках.

Суть в чём, ёпта? Есть у тебя общая идея — «надо что-то залогировать». Это наш LoggerCreator. А вот как именно это сделать — нахуярить в файл или в базу данных — решают уже его наследнички. Они переопределяют один-единственный метод createLogger(). Всё, больше от них ничего не надо.

// Вот смотри, абстрактный создатель. Он говорит: "Дети, я не ебу, какой логгер вам нужен, сделайте сами".
abstract class LoggerCreator {
    abstract public function createLogger(): Logger; // Вот этот самый фабричный метод, его реализуют дети.

    public function logMessage(string $message): void {
        $logger = $this->createLogger(); // А тут он просто пользуется тем, что ребёнок ему подсунул.
        $logger->log($message);
    }
}

Короче, если тебе нужно разнообразить создание одного объекта — это твой выбор. Один продукт, много способов его сварганить. Довольно просто, терпения ноль ебать на понимание.


Абстрактная фабрика — это уже не шутки, это целый стиль жизни, семейство продуктов.

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

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

// Это контракт на целый комплект.
interface GUIFactory {
    public function createButton(): Button;
    public function createCheckbox(): Checkbox;
    // ... и так далее, для всех виджетов
}

// Конкретная фабрика для Windows. Она, блядь, как конвейер, штампует только виндовые детали.
class WinFactory implements GUIFactory {
    public function createButton(): Button { return new WinButton(); } // Только WinButton!
    public function createCheckbox(): Checkbox { return new WinCheckbox(); } // Только WinCheckbox!
}

Клиентский код (renderUI) получает фабрику и, не парится, создаёт через неё всё, что нужно. Он абсолютно не ебёт, какие там конкретные классы кнопок и чекбоксов. Главное — они все будут от одной фабрики, а значит, в одном стиле. Гарантия совместимости, доверия ебать ноль, но система работает.

Итоговая разница, если по-простому:

  • Фабричный метод: «Эй, наследник, скажи мне, какой один объект мне тут нужно создать, а я дальше сам им воспользуюсь». Фокус на делегировании создания одного продукта.
  • Абстрактная фабрика: «Эй, фабрика, мне нужен полный комплект связанных между собой объектов (кнопка, чекбокс, меню), и чтобы всё было в одном стиле». Фокус на создании семейств совместимых продуктов.

Выбирай, исходя из задачи. Нужно варьировать один ингредиент — фабричный метод. Нужно гарантировать, что весь интерфейс будет выдержан в одном стиле — абстрактная фабрика, ёбана в рот. Всё гениальное просто, хотя с первого взгляда охуеть можно.