Что это такое
Паттерн Abstract Factory создаёт целые семейства связанных объектов, которые подходят друг к другу. Если фабричный метод создаёт один продукт, то абстрактная фабрика создаёт согласованный набор — и гарантирует, что части никогда не перемешаются.
Классический случай — оформление тем: светлая тема должна создавать светлые кнопки и светлые метки, но никогда не смесь.
Пример: фабрика тем
renderScreen принимает любую UIFactory и собирает из неё согласованный экран. Смена всего внешнего вида — это один аргумент, а смешать темы невозможно по самой конструкции.
Одна фабрика — одно согласованное семейство
Светлая тема создаёт только светлые части, тёмная — только тёмные. renderScreen никогда не меняется: она вызывает createLabel() и createButton() у той фабрики, которую ей передали.
Вывод: программа на TypeScript и захваченный вывод
interface Button {
render(): string
}
interface Label {
render(): string
}
// Абстрактная фабрика создаёт целое согласованное семейство.
interface UIFactory {
createButton(): Button
createLabel(): Label
}
class LightButton implements Button {
render(): string {
return "[ OK ] светлая кнопка"
}
}
class LightLabel implements Label {
render(): string {
return "привет светлая метка"
}
}
class DarkButton implements Button {
render(): string {
return "[ OK ] тёмная кнопка"
}
}
class DarkLabel implements Label {
render(): string {
return "привет тёмная метка"
}
}
class LightTheme implements UIFactory {
createButton(): Button {
return new LightButton()
}
createLabel(): Label {
return new LightLabel()
}
}
class DarkTheme implements UIFactory {
createButton(): Button {
return new DarkButton()
}
createLabel(): Label {
return new DarkLabel()
}
}
function renderScreen(factory: UIFactory): void {
console.log(factory.createLabel().render())
console.log(factory.createButton().render())
}
renderScreen(new LightTheme())
renderScreen(new DarkTheme())
Когда его применять
Применяйте, когда несколько объектов должны оставаться согласованными друг с другом: темы оформления, наборы виджетов для разных платформ, парные форматы импорта и экспорта.
Не применяйте, когда продуктам не нужно подходить друг к другу. Независимые объекты заслуживают независимых конструкторов, а не фабрики семейств.
Плюсы и минусы
Плюсы: согласованность семейства гарантирована; целые семейства заменяются одним значением; вызывающий код зависит только от интерфейсов.
Минусы: много интерфейсов и классов ради небольшой задачи; добавление нового продукта в семейство означает правку каждой фабрики.