Что такое паттерн ‘Абстрактная фабрика’ и когда его следует применять?

Ответ

Абстрактная фабрика — это порождающий паттерн проектирования, который предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретные классы.

Проблема

Представьте, что вы создаете UI-кит, который должен поддерживать несколько операционных систем (Windows, macOS). Вам нужны кнопки, чекбоксы и другие элементы, которые выглядят и ведут себя по-разному в каждой ОС. Если создавать объекты напрямую (button = WinButton()), ваш код будет жестко связан с конкретными классами, и добавление новой ОС потребует изменения всего клиентского кода.

Решение

Абстрактная фабрика предлагает создать общий интерфейс (GUIFactory) с методами для создания каждого продукта в семействе (create_button, create_checkbox). Затем для каждой ОС создается своя конкретная фабрика (WinFactory, MacFactory), которая реализует этот интерфейс и возвращает объекты, соответствующие данной ОС.

Клиентский код работает только с интерфейсом фабрики, не зная, какая конкретная фабрика ему передана.

Пример на Python

from abc import ABC, abstractmethod

# --- Абстрактные продукты ---
class Button(ABC):
    @abstractmethod
    def render(self) -> str:
        pass

class Checkbox(ABC):
    @abstractmethod
    def render(self) -> str:
        pass

# --- Абстрактная фабрика ---
class GUIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button:
        pass

    @abstractmethod
    def create_checkbox(self) -> Checkbox:
        pass

# --- Конкретные фабрики и продукты для Windows ---
class WinButton(Button):
    def render(self) -> str:
        return "Отрисовка кнопки в стиле Windows"

class WinCheckbox(Checkbox):
    def render(self) -> str:
        return "Отрисовка чекбокса в стиле Windows"

class WinFactory(GUIFactory):
    def create_button(self) -> Button:
        return WinButton()

    def create_checkbox(self) -> Checkbox:
        return WinCheckbox()

# --- Конкретные фабрики и продукты для macOS ---
class MacButton(Button):
    def render(self) -> str:
        return "Отрисовка кнопки в стиле macOS"

class MacCheckbox(Checkbox):
    def render(self) -> str:
        return "Отрисовка чекбокса в стиле macOS"

class MacFactory(GUIFactory):
    def create_button(self) -> Button:
        return MacButton()

    def create_checkbox(self) -> Checkbox:
        return MacCheckbox()

# --- Клиентский код ---
def client_code(factory: GUIFactory):
    button = factory.create_button()
    checkbox = factory.create_checkbox()
    print(button.render())
    print(checkbox.render())

# Используем фабрику для Windows
print("Клиент: работаю с Windows UI")
client_code(WinFactory())

# Используем фабрику для macOS
print("nКлиент: работаю с macOS UI")
client_code(MacFactory())

Когда использовать

  • Когда система не должна зависеть от того, как создаются, компонуются и представляются входящие в нее объекты.
  • Когда нужно работать с одним из нескольких семейств объектов, и эти семейства спроектированы для совместного использования.
  • Когда вы хотите предоставить библиотеку классов, раскрывая только их интерфейсы, но не реализацию.