Чем отличается фабрика от фабричного метода?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между паттернами "Фабрика" (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), которая является упрощённой базой для обоих описанных паттернов.