Как реализуется паттерн проектирования ‘Фабрика’ в Python?

«Как реализуется паттерн проектирования ‘Фабрика’ в Python?» — вопрос из категории Паттерны, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

В Python существует несколько вариаций этого паттерна.

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

Это не канонический паттерн из банды четырех (GoF), а скорее популярная идиома. Один класс или функция решает, какой объект создать, на основе переданного параметра.

Применение: Когда логика создания объектов несложная и не требует расширения через наследование.

class Dog:
    def speak(self): return "Woof!"

class Cat:
    def speak(self): return "Meow!"

# Простая фабрика в виде функции
def get_pet(pet_type: str):
    """Создает объект животного по его типу."""
    if pet_type == "dog":
        return Dog()
    elif pet_type == "cat":
        return Cat()
    raise ValueError("Unknown pet type")

# Использование
my_dog = get_pet("dog")
print(my_dog.speak()) # -> Woof!

2. Фабричный метод (Factory Method)

Это канонический паттерн. Он определяет абстрактный метод для создания объекта (factory_method), а конкретные реализации этого метода находятся в подклассах. Таким образом, создание объекта делегируется дочерним классам.

Применение: Когда класс не может заранее знать, объекты каких подклассов ему нужно создавать, или когда вы хотите дать пользователям возможность расширять вашу библиотеку.

from abc import ABC, abstractmethod

# Абстрактный продукт
class Animal(ABC):
    @abstractmethod
    def speak(self): pass

# Конкретные продукты
class Dog(Animal):
    def speak(self): return "Woof!"

class Cat(Animal):
    def speak(self): return "Meow!"

# Абстрактный создатель (фабрика)
class AnimalFactory(ABC):
    @abstractmethod
    def create_animal(self) -> Animal:
        pass

# Конкретные создатели
class DogFactory(AnimalFactory):
    def create_animal(self) -> Animal:
        return Dog()

class CatFactory(AnimalFactory):
    def create_animal(self) -> Animal:
        return Cat()

# Использование
def get_animal_from_factory(factory: AnimalFactory):
    animal = factory.create_animal()
    print(f"Created animal says: {animal.speak()}")

get_animal_from_factory(DogFactory()) # -> Created animal says: Woof!
get_animal_from_factory(CatFactory()) # -> Created animal says: Meow!

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

Этот паттерн позволяет создавать семейства взаимосвязанных объектов, не привязываясь к их конкретным классам. Он предоставляет интерфейс для создания целого набора продуктов.

Применение: Когда система должна быть независимой от того, как создаются, компонуются и представляются ее продукты.

# Пример: Фабрика для создания GUI элементов под разные ОС

# Абстрактные продукты
class Button(ABC):
    @abstractmethod
    def render(self): pass

class Checkbox(ABC):
    @abstractmethod
    def render(self): pass

# Абстрактная фабрика
class GUIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button: pass

    @abstractmethod
    def create_checkbox(self) -> Checkbox: pass

# Конкретная фабрика для Windows
class WinFactory(GUIFactory):
    def create_button(self) -> Button: return WinButton()
    def create_checkbox(self) -> Checkbox: return WinCheckbox()

# Конкретная фабрика для MacOS
class MacFactory(GUIFactory):
    def create_button(self) -> Button: return MacButton()
    def create_checkbox(self) -> Checkbox: return MacCheckbox()

# ... реализации конкретных продуктов WinButton, MacButton и т.д. ...

Основные преимущества паттерна:

  • Инкапсуляция: Скрывает логику создания объектов от клиентского кода.
  • Гибкость: Упрощает добавление новых типов продуктов, не изменяя существующий клиентский код.
  • Соблюдение принципов SOLID: Соответствует принципу открытости/закрытости (Open/Closed Principle) и принципу единственной ответственности (Single Responsibility Principle).