Весной стартует сезон найма, успей отхватить свой оффер!

Паттерн Абстрактная фабрика (Abstract Factory)

Абстрактная фабрика (Abstract Factory) — это порождающий паттерн проектирования, который предоставляет интерфейс для создания семейств взаимосвязанных объектов без указания конкретных классов. Этот паттерн особенно полезен, когда ваш код должен работать с разными «семействами» объектов, но при этом оставаться независимым от конкретных реализаций.

Идея:

«Абстрактная фабрика» помогает создавать продукты, принадлежащие к одному семейству, через общий интерфейс, скрывая детали реализации.


Когда применять «Абстрактную фабрику»?

  • Когда в программе должно существовать несколько «семейств» продуктов, которые используются совместно. Например, разные темы (Theme) в UI (светлая, тёмная) или различные движки (2D/3D).
  • Когда нужно создавать объекты в зависимости от конкретной конфигурации или среды выполнения (например, Web vs. Mobile), но код не должен зависеть от деталей этой конфигурации.
  • Когда нужно скрыть от клиента логику выбора конкретной реализации, чтобы её можно было легко изменить без затрагивания остального кода.

Принцип работы

1

1. Определение семейств продуктов

Сначала определяем типы продуктов, которые должны создаваться совместно. Например: Button, Checkbox, Modal для разных платформ или тем.

2

2. Создание абстрактных интерфейсов

Каждое семейство продуктов имеет абстрактные интерфейсы. Например: Button с методом render() и Checkbox с методом toggle().

3

3. Реализация конкретных продуктов

Для каждой платформы (или темы) создаются конкретные классы, реализующие эти интерфейсы. Например: MacButton, MacCheckbox и WinButton, WinCheckbox.

4

4. Абстрактная фабрика

Абстрактная фабрика определяет методы для создания продуктов (например, createButton(), createCheckbox()) и возвращает абстрактные типы. Конкретные фабрики (MacFactory, WinFactory) переопределяют эти методы, создавая соответствующие объекты.

5

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());

Источник

Абстрактная фабрика отлично подходит для крупных систем, где есть несколько вариантов одного и того же «семейства» продуктов. Она делает код гибким, позволяя подменять целые наборы объектов, не меняя основную логику. Однако из-за увеличения количества классов этот паттерн может быть избыточным, если вам нужно лишь изредка переключаться между реализациями или управлять небольшим количеством сущностей.

Подробнее про абстрактную фабрику можно почитать здесь.