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

ПРоблема
Логика создания объекта может становиться слишком запутанной и конструктор становится не информативным

Примеры:

- ряд обязательных и необязательных параметров, параметров со значениями по умолчанию
- параметр невозможно перегрузить одним и тем же набором аргументов с разными именами

Для решения таких задач можно передать тонкости создания объекта отдельному методы(фабричный метод) или отдельному классу (Фабрика). Также можно использовать иерархию Фабрик используя Абстрактную Фабрику
Описание
Абстрактная фабрика — порождающий шаблон проектирования, предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы.

Фабрика, которая группирует индивидуальные, но связанные/зависимые фабрики без указания их конкретных классов.
ПРимер
Опишем распространённый пример создания элементов интерфейса. Используем абстрактные классы для описания классов StatusBar, MainMenu. Создадим абстрактную фабрику GuiAbstractFactory, которая характеризует интерфейс для фабрик создания объектов.

Создадим фабрики WindowsGUIFactory и LinuxGUIFactory.

Класс Application описывает создания объектов интерфейса для Windows или Linux

Фабричный метод create_factory, который возвращает одну из фабрик в зависимости от указанного system_name

from abc import ABC, abstractmethod
from dataclasses import dataclass, field


@dataclass
class StatusBar(ABC):
    system: str

    @abstractmethod
    def create(self):
        pass

@dataclass
class MainMenu(ABC):
    system: str

    @abstractmethod
    def create(self):
        pass


@dataclass
class WindowsStatusBar(StatusBar):
    system: str = None

    def __post__init(self):
        self.system = 'Windows'

    def create(self) -> None:
        print(f'status bar {self.system}')

'''Windows class'''
@dataclass
class WindowsMainMenu(MainMenu):
    system: str = None

    def __post__init(self):
        self.system = 'Windows'

    def create(self) -> None:
        print(f'mainMenu {self.system}')


'''Linux class'''
@dataclass
class LinuxStatusBar(StatusBar):
    system: str = None

    def __post__init(self):
        self.system = 'Linux'

    def create(self) -> None:
        print(f'status bar {self.system}')


@dataclass
class LinuxMainMenu(MainMenu):
    system: str = None

    def __post__init(self):
        self.system = 'Linux'

    def create(self) -> None:
        print(f'mainMenu {self.system}')


'''Абстрактная фабрика'''
@dataclass
class GuiAbstractFactory(ABC):

    @abstractmethod
    def getStatusBar(self) -> StatusBar:
        pass

    @abstractmethod
    def getMainMenu(self) -> MainMenu:
        pass


'''Фабрики'''
@dataclass
class WindowsGUIFactory(GuiAbstractFactory):

    def getStatusBar(self) -> StatusBar:
        return WindowsStatusBar()

    def getMainMenu(self) -> MainMenu:
        return WindowsMainMenu()


@dataclass
class LinuxGUIFactory(GuiAbstractFactory):

    def getStatusBar(self) -> StatusBar:
        return LinuxStatusBar()

    def getMainMenu(self) -> MainMenu:
        return LinuxMainMenu()


@dataclass
class Application:
    gui_factory: GuiAbstractFactory

    def create_gui(self):
        status_bar = self.gui_factory.getStatusBar()
        main_menu = self.gui_factory.getMainMenu()
        status_bar.create()
        main_menu.create()


def create_factory(system_name: str) -> GuiAbstractFactory:
    factory_dict = {
        'Windows': WindowsGUIFactory(),
        'Linux': LinuxGUIFactory()
    }

    return factory_dict[system_name]


if __name__ == '__main__':
    system_name = 'Linux'
    ui = create_factory(system_name)
    app = Application(ui)
    app.create_gui()