Что это такое
Паттерн Абстрактная фабрика создаёт целые семейства связанных объектов, которые должны использоваться вместе. Если фабричный метод создаёт один продукт, то абстрактная фабрика создаёт согласованный набор — и гарантирует, что его части никогда не перемешаются.
Классический случай — оформление: светлая тема должна создавать светлые кнопки и светлые метки, но никогда не смесь из них.
Пример: фабрика тем
renderScreen принимает любую UIFactory и строит из неё согласованный экран. Полная смена внешнего вида — это один аргумент, а смешать темы невозможно по построению.
Одна фабрика — одно согласованное семейство
Светлая тема создаёт только светлые части, тёмная — только тёмные. renderScreen при этом не меняется.
Вывод: PHP-скрипт
<?php
interface Button {
public function render(): string;
}
interface Label {
public function render(): string;
}
// Абстрактная фабрика создаёт целое согласованное семейство.
interface UIFactory {
public function newButton(): Button;
public function newLabel(): Label;
}
class LightButton implements Button {
public function render(): string {
return "[ OK ] светлая кнопка";
}
}
class LightLabel implements Label {
public function render(): string {
return "hello светлая метка";
}
}
class DarkButton implements Button {
public function render(): string {
return "[ OK ] тёмная кнопка";
}
}
class DarkLabel implements Label {
public function render(): string {
return "hello тёмная метка";
}
}
class LightTheme implements UIFactory {
public function newButton(): Button {
return new LightButton();
}
public function newLabel(): Label {
return new LightLabel();
}
}
class DarkTheme implements UIFactory {
public function newButton(): Button {
return new DarkButton();
}
public function newLabel(): Label {
return new DarkLabel();
}
}
function renderScreen(UIFactory $f): void {
echo $f->newLabel()->render(), "\n";
echo $f->newButton()->render(), "\n";
}
renderScreen(new LightTheme());
renderScreen(new DarkTheme());
Когда использовать
Используйте, когда несколько объектов должны быть согласованы друг с другом: темы оформления, наборы виджетов для платформы, парные форматы импорта и экспорта.
Не используйте, когда продуктам не нужно соответствовать друг другу. Независимым объектам нужны независимые конструкторы, а не фабрика семейства.
Плюсы и минусы
Плюсы: согласованность семейства гарантирована; целые семейства подменяются одним значением; вызывающий код зависит только от интерфейсов.
Минусы: много интерфейсов и классов для небольшой задачи; добавление нового продукта в семейство требует правки каждой фабрики.