Что это такое
Паттерн Абстрактная фабрика (Abstract Factory) создаёт целые семейства связанных объектов, которые должны использоваться вместе. Если фабричный метод создаёт один продукт, то абстрактная фабрика создаёт согласованный набор — и гарантирует, что части никогда не будут перемешаны.
Классический пример — темы оформления: светлая тема должна создавать светлые кнопки и светлые метки, а не их смесь.
Пример: фабрика тем
render_screen принимает любую UIFactory и строит из неё согласованный экран. Чтобы сменить весь внешний вид, достаточно одного аргумента — а смешать темы невозможно по самой конструкции.
Одна фабрика — одно согласованное семейство
Светлая тема создаёт только светлые элементы, тёмная — только тёмные. render_screen при этом не меняется.
Вывод: полная программа на Python
from typing import Protocol
class Button(Protocol):
def render(self) -> str: ...
class Label(Protocol):
def render(self) -> str: ...
# Абстрактная фабрика создаёт целое согласованное семейство.
class UIFactory(Protocol):
def new_button(self) -> Button: ...
def new_label(self) -> Label: ...
class LightButton:
def render(self) -> str:
return "[ OK ] светлая кнопка"
class LightLabel:
def render(self) -> str:
return "hello светлая метка"
class DarkButton:
def render(self) -> str:
return "[ OK ] тёмная кнопка"
class DarkLabel:
def render(self) -> str:
return "hello тёмная метка"
class LightTheme:
def new_button(self) -> Button:
return LightButton()
def new_label(self) -> Label:
return LightLabel()
class DarkTheme:
def new_button(self) -> Button:
return DarkButton()
def new_label(self) -> Label:
return DarkLabel()
def render_screen(factory: UIFactory) -> None:
print(factory.new_label().render())
print(factory.new_button().render())
render_screen(LightTheme())
render_screen(DarkTheme())
Когда использовать
Используйте его, когда несколько объектов должны быть согласованы друг с другом — темы оформления, наборы виджетов для разных платформ, парные форматы импорта/экспорта.
Не используйте его, когда продукты не обязаны сочетаться. Независимым объектам нужны независимые конструкторы, а не фабрика семейств.
Плюсы и минусы
Плюсы: согласованность семейства гарантирована; целые семейства заменяются одним значением; вызывающий код зависит только от протоколов.
Минусы: много протоколов и классов для небольшой задачи; добавление нового продукта в семейство требует изменения каждой фабрики.