Фабричный метод на Python
Фабричный метод — это порождающий паттерн проектирования, который решает проблему создания различных продуктов, без указания конкретных классов продуктов.
Фабричный метод задаёт метод, который следует использовать вместо вызова оператора new
для создания объектов-продуктов. Подклассы могут переопределить этот метод, чтобы изменять тип создаваемых продуктов.
Сложность:
Популярность:
Применимость: Паттерн можно часто встретить в любом Python-коде, где требуется гибкость при создании продуктов.
Признаки применения паттерна: Фабричный метод можно определить по создающим методам, которые возвращают объекты продуктов через абстрактные типы или интерфейсы. Это позволяет переопределять типы создаваемых продуктов в подклассах.
Концептуальный пример
Этот пример показывает структуру паттерна Фабричный метод , а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.py: Пример структуры паттерна
from __future__ import annotations
from abc import ABC, abstractmethod
class Creator(ABC):
"""
Класс Создатель объявляет фабричный метод, который должен возвращать объект
класса Продукт. Подклассы Создателя обычно предоставляют реализацию этого
метода.
"""
@abstractmethod
def factory_method(self):
"""
Обратите внимание, что Создатель может также обеспечить реализацию
фабричного метода по умолчанию.
"""
pass
def some_operation(self) -> str:
"""
Также заметьте, что, несмотря на название, основная обязанность
Создателя не заключается в создании продуктов. Обычно он содержит
некоторую базовую бизнес-логику, которая основана на объектах Продуктов,
возвращаемых фабричным методом. Подклассы могут косвенно изменять эту
бизнес-логику, переопределяя фабричный метод и возвращая из него другой
тип продукта.
"""
# Вызываем фабричный метод, чтобы получить объект-продукт.
product = self.factory_method()
# Далее, работаем с этим продуктом.
result = f"Creator: The same creator's code has just worked with {product.operation()}"
return result
"""
Конкретные Создатели переопределяют фабричный метод для того, чтобы изменить тип
результирующего продукта.
"""
class ConcreteCreator1(Creator):
"""
Обратите внимание, что сигнатура метода по-прежнему использует тип
абстрактного продукта, хотя фактически из метода возвращается конкретный
продукт. Таким образом, Создатель может оставаться независимым от конкретных
классов продуктов.
"""
def factory_method(self) -> Product:
return ConcreteProduct1()
class ConcreteCreator2(Creator):
def factory_method(self) -> Product:
return ConcreteProduct2()
class Product(ABC):
"""
Интерфейс Продукта объявляет операции, которые должны выполнять все
конкретные продукты.
"""
@abstractmethod
def operation(self) -> str:
pass
"""
Конкретные Продукты предоставляют различные реализации интерфейса Продукта.
"""
class ConcreteProduct1(Product):
def operation(self) -> str:
return "{Result of the ConcreteProduct1}"
class ConcreteProduct2(Product):
def operation(self) -> str:
return "{Result of the ConcreteProduct2}"
def client_code(creator: Creator) -> None:
"""
Клиентский код работает с экземпляром конкретного создателя, хотя и через
его базовый интерфейс. Пока клиент продолжает работать с создателем через
базовый интерфейс, вы можете передать ему любой подкласс создателя.
"""
print(f"Client: I'm not aware of the creator's class, but it still works.\n"
f"{creator.some_operation()}", end="")
if __name__ == "__main__":
print("App: Launched with the ConcreteCreator1.")
client_code(ConcreteCreator1())
print("\n")
print("App: Launched with the ConcreteCreator2.")
client_code(ConcreteCreator2())
Output.txt: Результат выполнения
App: Launched with the ConcreteCreator1.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct1}
App: Launched with the ConcreteCreator2.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct2}