Вступление
В этой статье мы углубимся в шаблон проектирования фабричного метода, реализованный на Python.
Шаблоны проектирования определяют проверенные временем решения различных повторяющихся проблем в разработке программного обеспечения. Они не представляют собой реальный код, а скорее способы, с помощью которых мы можем организовать наш код для достижения оптимальных результатов.
В мире ограниченных ресурсов шаблоны проектирования помогают нам достичь максимальных результатов с наименьшим количеством используемых ресурсов. Также важно отметить, что шаблоны проектирования применимы не ко всем ситуациям, и очень важно оценить имеющуюся проблему, чтобы выбрать лучший подход для этого конкретного сценария.
Шаблоны проектирования делятся на несколько широких категорий, но в основном это шаблоны создания, структурные шаблоны и поведенческие шаблоны.
Шаблон Factory Method - это шаблон творческого проектирования .
Шаблон проектирования фабричного метода
Определение
Фабричный метод используется в объектно-ориентированном программировании как средство предоставления фабричных интерфейсов для создания объектов. Эти интерфейсы определяют общую структуру, но не инициализируют объекты. Инициализация предоставляется более конкретным подклассам.
Родительский класс / интерфейс содержит все стандартное и универсальное поведение, которое может быть общим для подклассов разных типов. Подкласс, в свою очередь, отвечает за определение и создание экземпляра объекта на основе суперкласса.
Мотивация
Основная мотивация, лежащая в основе шаблона проектирования фабричного метода, заключается в улучшении слабой связи в коде путем создания абстрактного класса, который будет использоваться для создания различных типов объектов, которые имеют общие атрибуты и функции.
Это приводит к повышенной гибкости и повторному использованию кода, поскольку общие функциональные возможности не будут переписаны, будучи унаследованными от того же класса. Этот шаблон проектирования также известен как виртуальный конструктор .
Шаблон проектирования Factory Method обычно используется в библиотеках, позволяя клиентам выбирать, какой подкласс или тип объекта создать с помощью абстрактного класса.
Заводской метод получит информацию о требуемом объекте, создаст его экземпляр и вернет объект указанного типа. Это дает нашему приложению или библиотеке единую точку взаимодействия с другими программами или фрагментами кода, тем самым инкапсулируя наши функции создания объектов.
Реализация фабричного метода
Наша программа будет библиотекой, используемой для обработки объектов формы с точки зрения создания и других операций, таких как добавление цвета и вычисление площади формы.
Пользователи должны иметь возможность использовать нашу библиотеку для создания новых объектов. Мы можем начать с создания отдельных фигур и использовать их как есть, но это будет означать, что придется переписывать большую часть общей логики для каждой формы, которая у нас есть.
Первым шагом к решению этого повторения будет создание родительского
класса формы, который имеет такие методы, как calculate_area()
и
calculate_perimeter()
, а также такие свойства, как размеры.
Затем конкретные объекты формы унаследуются от нашего базового класса. Чтобы создать фигуру, нам нужно будет определить, какая форма требуется, и создать для нее подкласс.
Мы начнем с создания абстрактного класса для представления общей формы:
import abc
class Shape(metaclass=abc.ABCMeta):
@abc.abstractmethod
def calculate_area(self):
pass
@abc.abstractmethod
def calculate_perimeter(self):
pass
Это базовый класс для всех наших фигур. Давайте продолжим и создадим несколько конкретных, более конкретных форм:
class Rectangle(Shape):
def __init__(self, height, width):
self.height = height
self.width = width
def calculate_area(self):
return self.height * self.width
def calculate_perimeter(self):
return 2 * (self.height + self.width)
class Square(Shape):
def __init__(self, width):
self.width = width
def calculate_area(self):
return self.width ** 2
def calculate_perimeter(self):
return 4 * self.width
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def calculate_area(self):
return 3.14 * self.radius * self.radius
def calculate_perimeter(self):
return 2 * 3.14 * self.radius
Пока что мы создали абстрактный класс и расширили его, чтобы он соответствовал различным формам, которые будут доступны в нашей библиотеке. Чтобы создавать различные объекты-формы, клиенты должны знать имена и детали наших фигур и отдельно выполнять создание.
Здесь в игру вступает заводской метод.
Шаблон проектирования Factory Method поможет нам абстрагироваться от доступных форм от клиента, то есть клиенту не нужно знать все доступные формы, а только создавать то, что им нужно, во время выполнения. Это также позволит нам централизовать и инкапсулировать создание объекта.
Давайте добьемся этого, создав ShapeFactory
который будет
использоваться для создания определенных классов фигур на основе ввода
клиента:
class ShapeFactory:
def create_shape(self, name):
if name == 'circle':
radius = input("Enter the radius of the circle: ")
return Circle(float(radius))
elif name == 'rectangle':
height = input("Enter the height of the rectangle: ")
width = input("Enter the width of the rectangle: ")
return Rectangle(int(height), int(width))
elif name == 'square':
width = input("Enter the width of the square: ")
return Square(int(width))
Это наш интерфейс для творчества. Мы не вызываем конструкторы конкретных классов, мы вызываем Factory и просим ее создать форму.
Наша ShapeFactory
работает, получая информацию о форме, такую как имя
и требуемые размеры. Затем наш фабричный метод create_shape()
будет
использоваться для создания и возврата готовых объектов желаемой формы.
Заказчику не нужно ничего знать о создании объекта или его особенностях. Используя объект фабрики, они могут создавать объекты с минимальными знаниями о том, как они работают:
def shapes_client():
shape_factory = ShapeFactory()
shape_name = input("Enter the name of the shape: ")
shape = shape_factory.create_shape(shape_name)
print(f"The type of object created: {type(shape)}")
print(f"The area of the {shape_name} is: {shape.calculate_area()}")
print(f"The perimeter of the {shape_name} is: {shape.calculate_perimeter()}")
Выполнение этого кода приведет к:
Enter the name of the shape: circle
Enter the radius of the circle: 7
The type of object created: <class '__main__.Circle'>
The area of the circle is: 153.86
The perimeter of the circle is: 43.96
Или мы могли бы построить другую фигуру:
Enter the name of the shape: square
Enter the width of the square: 5
The type of object created: <class '__main__.Square'>
The area of the square is: 25
The perimeter of the square is: 20
Стоит отметить, что помимо того, что клиенту не нужно много знать о
процессе создания - когда мы хотим создать экземпляр объекта, мы не
вызываем конструктор класса. Мы просим фабрику сделать это за нас на
основе информации, которую мы передаем функции create_shape()
.
Плюсы и минусы
Плюсы
Одним из основных преимуществ использования шаблона проектирования Factory Method является то, что наш код становится слабосвязанным, поскольку большинство компонентов нашего кода не знают о других компонентах той же кодовой базы.
В результате получается код, который легко понять и протестировать, а также добавить дополнительные функции к определенным компонентам, не затрагивая и не нарушая работу всей программы.
Шаблон проектирования фабричного метода также помогает поддерживать принцип единой ответственности, в котором классы и объекты, которые обрабатывают определенные функции, приводят к улучшению кода.
Минусы
Создание большего количества классов в конечном итоге приводит к снижению читабельности. В сочетании с абстрактной фабрикой (фабрикой фабрик) код скоро станет многословным, но поддерживаемым.
Заключение
В заключение, шаблон проектирования фабричного метода позволяет нам создавать объекты без указания точного класса, необходимого для создания конкретного объекта. Это позволяет нам отделить наш код и повысить его возможность повторного использования.
Важно отметить, что, как и любой другой шаблон проектирования, он подходит только для определенных ситуаций, а не для каждого сценария разработки. Оценка ситуации имеет решающее значение перед принятием решения о реализации шаблона проектирования фабричного метода, чтобы воспользоваться преимуществами этого шаблона.