← Назад к вопросам

Чем отличается фабрика от фабричного метода?

2.0 Middle🔥 162 комментариев
#Архитектура и паттерны#ООП

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между паттернами "Фабрика" (Factory) и "Фабричный метод" (Factory Method)

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

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

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

Ключевые характеристики:

  • Инкапсулирует создание одного конкретного продукта.
  • Центральный элемент — абстрактный метод createProduct() (или подобный), объявленный в базовом классе (Создателе).
  • Каждый подкласс-создатель реализует этот метод, возвращая свой конкретный экземпляр продукта.
  • Логика, использующая продукт, остаётся в базовом классе и работает через абстрактный интерфейс продукта.

Пример на PHP:

<?php
// Абстрактный класс Продукта
abstract class Transport {
    abstract public function deliver(): string;
}

// Конкретные продукты
class Truck extends Transport {
    public function deliver(): string {
        return "Доставка по дороге в коробке.";
    }
}

class Ship extends Transport {
    public function deliver(): string {
        return "Доставка по морю в контейнере.";
    }
}

// Абстрактный класс Создателя с Фабричным методом
abstract class Logistics {
    // ФАБРИЧНЫЙ МЕТОД
    abstract public function createTransport(): Transport;

    // Бизнес-логика, зависящая от продукта
    public function planDelivery(): string {
        $transport = $this->createTransport(); // Использование фабричного метода
        return "Планирование логистики: " . $transport->deliver();
    }
}

// Конкретные создатели
class RoadLogistics extends Logistics {
    public function createTransport(): Transport {
        return new Truck();
    }
}

class SeaLogistics extends Logistics {
    public function createTransport(): Transport {
        return new Ship();
    }
}

// Клиентский код
$roadLogistics = new RoadLogistics();
echo $roadLogistics->planDelivery(); // Создаст и использует Truck

$seaLogistics = new SeaLogistics();
echo $seaLogistics->planDelivery(); // Создаст и использует Ship
?>

В этом примере выбор типа создаваемого Transport определяется классом создателя (RoadLogistics или SeaLogistics).

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

Обычно под "Фабрикой" в этом контексте подразумевают паттерн "Абстрактная фабрика". Это паттерн уровня объектов, который предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов.

Ключевые характеристики:

  • Создаёт целое семейство продуктов (например, Chair + Sofa + CoffeeTable).
  • Центральный элемент — интерфейс или абстрактный класс АбстрактнойФабрики с набором методов для создания каждого продукта семейства (createChair(), createSofa()).
  • Каждая конкретная фабрика реализует этот интерфейс, создавая совместимое семейство продуктов (все продукты в стиле Modern или все в стиле Victorian).
  • Акцент на совместимости создаваемых объектов.

Пример на PHP:

<?php
// Семейство продуктов: Кресла
interface Chair {
    public function sitOn(): string;
    public function hasLegs(): bool;
}

class ModernChair implements Chair {
    public function sitOn(): string { return "Сидеть на современном кресле."; }
    public function hasLegs(): bool { return false; } // Может быть без ножек
}

class VictorianChair implements Chair {
    public function sitOn(): string { return "Сидеть на викторианском кресле."; }
    public function hasLegs(): bool { return true; } // Обязательно с резными ножками
}

// Семейство продуктов: Диваны
interface Sofa {
    public function lieOn(): string;
}

class ModernSofa implements Sofa {
    public function lieOn(): string { return "Лежать на современном диване."; }
}
class VictorianSofa implements Sofa { /* ... */ }

// АБСТРАКТНАЯ ФАБРИКА
interface FurnitureFactory {
    public function createChair(): Chair;
    public function createSofa(): Sofa;
}

// Конкретные фабрики для целых семейств
class ModernFurnitureFactory implements FurnitureFactory {
    public function createChair(): Chair {
        return new ModernChair();
    }
    public function createSofa(): Sofa {
        return new ModernSofa();
    }
}

class VictorianFurnitureFactory implements FurnitureFactory {
    public function createChair(): Chair {
        return new VictorianChair();
    }
    public function createSofa(): Sofa {
        return new VictorianSofa();
    }
}

// Клиентский код
function createFurnitureSuite(FurnitureFactory $factory) {
    $chair = $factory->createChair();
    $sofa = $factory->createSofa();

    echo $chair->sitOn() . "\n";
    echo $sofa->lieOn() . "\n";
    // Гарантировано, что chair и sofa будут выдержаны в одном стиле (Modern или Victorian)
}

$modernFactory = new ModernFurnitureFactory();
createFurnitureSuite($modernFactory); // Всё будет в современном стиле
?>

🆚 Сводка ключевых отличий

АспектФабричный метод (Factory Method)Абстрактная фабрика (Abstract Factory)
ЦельСоздание одного продукта, тип которого определяется подклассом.Создание семейств взаимосвязанных продуктов.
УровеньПаттерн уровня класса (работает через наследование).Паттерн уровня объекта (работает через композицию).
РеализацияОдин абстрактный/виртуальный метод в базовом классе.Интерфейс или абстрактный класс с набором методов (по одному на каждый тип продукта в семействе).
РасширениеДля добавления нового продукта создаётся новый подкласс создателя.Для добавления нового семейства продуктов создаётся новая конкретная фабрика, реализующая интерфейс. Сложнее добавить новый тип продукта (придётся менять все фабрики).
Использование в PHPЧасто встречается в ORM (например, $user->createQuery() в Doctrine), фреймворках для создания специфичных объектов.Идеален для создания целостных комплектующих: UI-киты (темы оформления), кроссплатформенные элементы GUI, комплекты поставки для разных сред (Dev/Prod).

🎯 Практический вывод

  • Используйте фабричный метод, когда процесс создания объекта должен быть отделён от основного кода, и вы хотите предоставить подклассам возможность определять, какой конкретный класс инстанцировать. Это более простой и распространённый паттерн.
  • Используйте абстрактную фабрику, когда ваша система должна быть независима от способа создания, компоновки и представления целых семейств продуктов, и эти семейства должны использоваться вместе. Это "фабрика фабрик" для обеспечения согласованности.

В терминологии иногда возникает путаница: "Простая фабрика" (Simple Factory) — это вообще не паттерн, а идиома (отдельный класс с одним методом, выбирающим объект для создания через switch или if), которая является упрощённой базой для обоих описанных паттернов.

Чем отличается фабрика от фабричного метода? | PrepBro