← Назад к вопросам

Что ожидается на выходе у шаблона фабрика?

1.3 Junior🔥 101 комментариев
#DevOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что ожидается на выходе у шаблона Фабрика

Factory Pattern (Фабрика) — один из основных паттернов проектирования. Это паттерн для создания объектов без указания их точных классов. Рассмотрю все его варианты и результаты.

1. Simple Factory (Простая фабрика)

На выходе: Один объект нужного типа в зависимости от параметра.

from abc import ABC, abstractmethod

# Определяем интерфейс
class Transport(ABC):
    @abstractmethod
    def deliver(self) -> str:
        pass

# Конкретные классы
class Car(Transport):
    def deliver(self) -> str:
        return "Доставка машиной по дороге"

class Ship(Transport):
    def deliver(self) -> str:
        return "Доставка кораблём по морю"

class Plane(Transport):
    def deliver(self) -> str:
        return "Доставка самолётом по воздуху"

# ФАБРИКА — возвращает нужный объект
class TransportFactory:
    @staticmethod
    def create_transport(transport_type: str) -> Transport:
        """На выходе: объект нужного класса"""
        if transport_type == "car":
            return Car()
        elif transport_type == "ship":
            return Ship()
        elif transport_type == "plane":
            return Plane()
        else:
            raise ValueError(f"Неизвестный тип: {transport_type}")

# Использование
factory = TransportFactory()
transport = factory.create_transport("car")  # На выходе: объект Car
print(transport.deliver())  # "Доставка машиной по дороге"

На выходе:

  • ✅ Объект нужного типа
  • ✅ Имплементирует общий интерфейс
  • ✅ Готов к использованию

2. Factory Method (Метод фабрика)

На выходе: Объект, созданный через виртуальный метод подклассов.

from abc import ABC, abstractmethod

# Интерфейс для фабрики
class Creator(ABC):
    @abstractmethod
    def create_product(self):
        """Метод фабрика — должен вернуть Product"""
        pass
    
    def business_logic(self):
        """Бизнес-логика использует результат фабрики"""
        product = self.create_product()  # На выходе: нужный Product
        return f"Creator работает с {product.operation()}"

# Интерфейс для продукта
class Product(ABC):
    @abstractmethod
    def operation(self) -> str:
        pass

# Конкретные создатели
class ConcreteCreatorA(Creator):
    def create_product(self) -> Product:
        """На выходе: ConcreteProductA"""
        return ConcreteProductA()

class ConcreteCreatorB(Creator):
    def create_product(self) -> Product:
        """На выходе: ConcreteProductB"""
        return ConcreteProductB()

# Конкретные продукты
class ConcreteProductA(Product):
    def operation(self) -> str:
        return "Результат продукта A"

class ConcreteProductB(Product):
    def operation(self) -> str:
        return "Результат продукта B"

# Использование
creator_a = ConcreteCreatorA()
print(creator_a.business_logic())  # На выходе: ConcreteProductA

creator_b = ConcreteCreatorB()
print(creator_b.business_logic())  # На выходе: ConcreteProductB

На выходе:

  • ✅ Product нужного типа
  • ✅ Выбор типа делегирован подклассу
  • ✅ Слабая связанность

3. Abstract Factory (Абстрактная фабрика)

На выходе: Семейство связанных объектов.

from abc import ABC, abstractmethod

# СЕМЕЙСТВО ПРОДУКТОВ 1
class Button(ABC):
    @abstractmethod
    def paint(self) -> str:
        pass

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

# Windows реализация
class WindowsButton(Button):
    def paint(self) -> str:
        return "Отрисовка Windows кнопки"

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

# Mac реализация
class MacButton(Button):
    def paint(self) -> str:
        return "Отрисовка Mac кнопки"

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

# АБСТРАКТНАЯ ФАБРИКА
class GUIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button:
        pass
    
    @abstractmethod
    def create_checkbox(self) -> Checkbox:
        pass

# Конкретные фабрики
class WindowsFactory(GUIFactory):
    def create_button(self) -> Button:
        return WindowsButton()  # На выходе: WindowsButton
    
    def create_checkbox(self) -> Checkbox:
        return WindowsCheckbox()  # На выходе: WindowsCheckbox

class MacFactory(GUIFactory):
    def create_button(self) -> Button:
        return MacButton()  # На выходе: MacButton
    
    def create_checkbox(self) -> Checkbox:
        return MacCheckbox()  # На выходе: MacCheckbox

# Использование
def render_ui(factory: GUIFactory):
    """На выходе фабрики: СОГЛАСОВАННОЕ СЕМЕЙСТВО объектов"""
    button = factory.create_button()
    checkbox = factory.create_checkbox()
    
    print(button.paint())
    print(checkbox.paint())

# На выходе всей функции: согласованный UI
windows_factory = WindowsFactory()
render_ui(windows_factory)
# На выходе: WindowsButton + WindowsCheckbox (согласованы!)

mac_factory = MacFactory()
render_ui(mac_factory)
# На выходе: MacButton + MacCheckbox (согласованы!)

На выходе:

  • ✅ Семейство связанных объектов
  • ✅ Все объекты из одного "семейства" (Windows/Mac)
  • ✅ Гарантирована совместимость

4. Практический пример: Система логирования

from abc import ABC, abstractmethod
from typing import Any

# Интерфейсы
class Logger(ABC):
    @abstractmethod
    def log(self, message: str) -> None:
        pass

class Handler(ABC):
    @abstractmethod
    def handle(self, record: dict) -> None:
        pass

# Конкретные логгеры
class ConsoleLogger(Logger):
    def log(self, message: str) -> None:
        print(f"[CONSOLE] {message}")

class FileLogger(Logger):
    def __init__(self, filename: str = "app.log"):
        self.filename = filename
    
    def log(self, message: str) -> None:
        with open(self.filename, "a") as f:
            f.write(f"[FILE] {message}\\n")

class DatabaseLogger(Logger):
    def log(self, message: str) -> None:
        # Имитация сохранения в БД
        print(f"[DB] Сохраняю в базу: {message}")

# ФАБРИКА ЛОГГЕРОВ
class LoggerFactory:
    _loggers = {
        "console": ConsoleLogger,
        "file": FileLogger,
        "database": DatabaseLogger,
    }
    
    @classmethod
    def create_logger(cls, logger_type: str, **kwargs) -> Logger:
        """На выходе: объект Logger нужного типа"""
        if logger_type not in cls._loggers:
            raise ValueError(f"Неизвестный тип логгера: {logger_type}")
        
        logger_class = cls._loggers[logger_type]
        return logger_class(**kwargs)  # На выходе!
    
    @classmethod
    def register_logger(cls, name: str, logger_class: type) -> None:
        """Возможность расширить фабрику"""
        cls._loggers[name] = logger_class

# Использование
logger = LoggerFactory.create_logger("console")  # На выходе: ConsoleLogger
logger.log("Это сообщение в консоль")

file_logger = LoggerFactory.create_logger("file", filename="debug.log")  # На выходе: FileLogger
file_logger.log("Это сообщение в файл")

db_logger = LoggerFactory.create_logger("database")  # На выходе: DatabaseLogger
db_logger.log("Это сообщение в БД")

5. Фабрика в реальных проектах

# Django ORM: Фабрика для создания моделей
from django.db import models

class User(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()

# На выходе: объект User из БД
user = User.objects.get(id=1)  # Фабрика!
users = User.objects.filter(email__contains="gmail")  # Фабрика!

# SQLAlchemy Session: Фабрика для сессий
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

engine = create_engine("postgresql://user:password@localhost/db")
SessionFactory = sessionmaker(bind=engine)

# На выходе: новая сессия
session = SessionFactory()  # Фабрика!
user = session.query(User).get(1)

# FastAPI dependency injection: Фабрика для зависимостей
from fastapi import Depends, FastAPI

app = FastAPI()

def get_db():
    """Фабрика для БД сессий"""
    db = SessionLocal()
    try:
        yield db  # На выходе: сессия БД
    finally:
        db.close()

@app.get("/users/{user_id}")
def get_user(user_id: int, db = Depends(get_db)):  # На выходе: db сессия
    return db.query(User).get(user_id)

Сравнение типов фабрик

ТипНа выходеКогда использовать
Simple FactoryОдин объектПростая логика выбора типа
Factory MethodОдин объект (через подклассы)Разные подклассы создают разные объекты
Abstract FactoryСемейство объектовСвязанные семейства (Windows/Mac)

Ключевые свойства на выходе

class FactoryPattern:
    """
    Что всегда должно быть на выходе фабрики?
    """
    
    @staticmethod
    def expectations():
        return {
            'type': 'Объект нужного класса или интерфейса',
            'ready_to_use': 'Полностью инициализирован',
            'interface': 'Реализует нужный контракт (ABC)',
            'no_client_knowledge': 'Клиент не знает точный тип',
            'extensible': 'Легко добавлять новые типы',
            'decoupled': 'Низкая связанность с кодом',
        }

Итоговый ответ

На выходе фабрики ожидается:

  1. Объект нужного типа (готовый к использованию)
  2. Реализация общего интерфейса (Abstract Base Class)
  3. Отсутствие прямой зависимости от конкретного класса
  4. Гибкость — легко добавлять новые типы
  5. Инкапсуляция логики создания объектов

Фабрика скрывает сложность создания и позволяет менять реализацию без изменения кода, который её использует. Это основной смысл паттерна.