Простая фабрика

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

Примеры:

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

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

Простая фабрика генерирует экземпляр для клиента, не раскрывая логики. Это может понадобиться когда у вас становится много фабричных методов, которые хочется сгруппировать в отдельные сущности.
Пример
При указании координат точки возможно использовать два подхода:

1) Указать координаты в Декартовой системе координат
2) Указать координаты в Полярной системе координат

Для этого опишем два фабричных метода, которые позволяют при создании объекта использовать разную логику и сгруппируем их в классе Фабрики.

Обращение к фабричным методам теперь идет через указания класса фабрики.

p1 = Point.Factory.new_cartesian_point(5, 6)
p2 = Point.Factory.new_polar_point(7, 8)

Так получается сгруппировать несколько методов создания объекта Point в один объект. Допустим у нас появятся дополнительные методы создания точки, для этого мы создадим другую фабрику и разместим методы в ней.
Создание класса для группировки фабричных методов

from dataclasses import dataclass
from math import cos, sin


@dataclass
class Point:
    x: float
    y: float

    def __str__(self):
        return f'x: {self.x}, y: {self.y}'

    class Factory:
        @staticmethod
        def new_cartesian_point(x, y):
            return Point(x, y)

        @staticmethod
        def new_polar_point(rho, theta):
            return Point(rho * sin(theta), rho * cos(theta))


if __name__ == '__main__':
    p1 = Point.Factory.new_cartesian_point(5, 6)
    p2 = Point.Factory.new_polar_point(7, 8)
    print(p1)
    print(p2)