Паттерн Абстрактная фабрика (Abstract Factory)
Абстрактная фабрика (Abstract Factory) — это порождающий паттерн проектирования, который предоставляет интерфейс для создания семейств взаимосвязанных объектов без указания конкретных классов. Этот паттерн особенно полезен, когда ваш код должен работать с разными «семействами» объектов, но при этом оставаться независимым от конкретных реализаций.
Идея:
«Абстрактная фабрика» помогает создавать продукты, принадлежащие к одному семейству, через общий интерфейс, скрывая детали реализации.
Когда применять «Абстрактную фабрику»?
- Когда в программе должно существовать несколько «семейств» продуктов, которые используются совместно. Например, разные темы (Theme) в UI (светлая, тёмная) или различные движки (2D/3D).
- Когда нужно создавать объекты в зависимости от конкретной конфигурации или среды выполнения (например, Web vs. Mobile), но код не должен зависеть от деталей этой конфигурации.
- Когда нужно скрыть от клиента логику выбора конкретной реализации, чтобы её можно было легко изменить без затрагивания остального кода.
Принцип работы
1. Определение семейств продуктов
Сначала определяем типы продуктов, которые должны создаваться совместно. Например: Button
, Checkbox
, Modal
для разных платформ или тем.
2. Создание абстрактных интерфейсов
Каждое семейство продуктов имеет абстрактные интерфейсы. Например: Button
с методом render()
и Checkbox
с методом toggle()
.
3. Реализация конкретных продуктов
Для каждой платформы (или темы) создаются конкретные классы, реализующие эти интерфейсы. Например: MacButton
, MacCheckbox
и WinButton
, WinCheckbox
.
4. Абстрактная фабрика
Абстрактная фабрика определяет методы для создания продуктов (например, createButton()
, createCheckbox()
) и возвращает абстрактные типы. Конкретные фабрики (MacFactory, WinFactory) переопределяют эти методы, создавая соответствующие объекты.
5. Клиентский код
Клиент работает только с абстрактной фабрикой и абстрактными продуктами, не привязываясь к конкретным реализациям. Выбор фабрики (Mac vs. Win) можно конфигурировать, не меняя остальной код.
Пример (TypeScript)
// 1. Абстрактные интерфейсы продуктов
interface Button {
render(): void;
}
interface Checkbox {
toggle(): void;
}
// 2. Конкретные продукты
class MacButton implements Button {
render(): void {
console.log("Mac button rendered");
}
}
class WinButton implements Button {
render(): void {
console.log("Windows button rendered");
}
}
class MacCheckbox implements Checkbox {
toggle(): void {
console.log("Mac checkbox toggled");
}
}
class WinCheckbox implements Checkbox {
toggle(): void {
console.log("Windows checkbox toggled");
}
}
// 3. Абстрактная фабрика
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
// 4. Конкретные фабрики
class MacFactory implements GUIFactory {
createButton(): Button {
return new MacButton();
}
createCheckbox(): Checkbox {
return new MacCheckbox();
}
}
class WinFactory implements GUIFactory {
createButton(): Button {
return new WinButton();
}
createCheckbox(): Checkbox {
return new WinCheckbox();
}
}
// 5. Клиентский код
function runApp(factory: GUIFactory) {
const button = factory.createButton();
button.render();
const checkbox = factory.createCheckbox();
checkbox.toggle();
}
// Можно легко подменять фабрику
// Mac UI
runApp(new MacFactory());
// Windows UI
runApp(new WinFactory());
Источник
Абстрактная фабрика отлично подходит для крупных систем, где есть несколько вариантов одного и того же «семейства» продуктов. Она делает код гибким, позволяя подменять целые наборы объектов, не меняя основную логику. Однако из-за увеличения количества классов этот паттерн может быть избыточным, если вам нужно лишь изредка переключаться между реализациями или управлять небольшим количеством сущностей.
Подробнее про абстрактную фабрику можно почитать здесь.