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