Создание объекта через JsonExporter() привязывает код к конкретному классу. Порождающие паттерны переносят решение «какой класс и как?» в одно место, чтобы клиенты зависели только от интерфейса. В уроке: простая фабрика, фабричный метод, абстрактная фабрика и питоничные способы их записи.

Проблема: растущая цепочка if

Каждый новый формат меняет export, а каждый вызывающий повторяет ветвление. Функция смешивает выбор формата и его реализацию (см. OCP).

python
import json

def export(rows, fmt):
    if fmt == "json":
        return json.dumps(rows)
    elif fmt == "csv":
        return "\n".join(",".join(str(v) for v in r.values()) for r in rows)
    raise ValueError(f"unknown format: {fmt}")

rows = [{"id": 1, "name": "Ann"}, {"id": 2, "name": "Bob"}]
print(export(rows, "json"))
print(export(rows, "csv"))
text
[{"id": 1, "name": "Ann"}, {"id": 2, "name": "Bob"}]
1,Ann
2,Bob

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

Сделайте каждый формат классом с одним методом dump, а имя в класс переводит одна функция. Словарь заменяет цепочку if, неизвестное имя даёт одну понятную ошибку. Это не паттерн GoF, но он решает большинство реальных задач.

python
import json

class JsonExporter:
    def dump(self, rows): return json.dumps(rows)

class CsvExporter:
    def dump(self, rows):
        return "\n".join(",".join(str(v) for v in r.values()) for r in rows)

def make_exporter(fmt):
    exporters = {"json": JsonExporter, "csv": CsvExporter}
    try:
        return exporters[fmt]()
    except KeyError:
        raise ValueError(f"unknown format: {fmt}") from None