Паттерн «Фабрика»
Часть раздела Объектно-ориентированное программирование путешествия по Python на Coddy. Урок 46 из 64.
Паттерн «Фабрика» создаёт объекты, не указывая их точный класс. Вместо прямого вызова конструкторов ты используешь фабричный метод, который определяет, какой класс создать.
Вот простые классы продуктов:
class Car:
def __init__(self, brand):
self.brand = brand
self.type = "Car"
def info(self):
return f"{self.type}: {self.brand}"
class Bike:
def __init__(self, brand):
self.brand = brand
self.type = "Bike"
def info(self):
return f"{self.type}: {self.brand}"Создайте класс-фабрику для создания этих объектов:
class VehicleFactory:
def create_vehicle(self, vehicle_type, brand):
if vehicle_type == "car":
return Car(brand)
elif vehicle_type == "bike":
return Bike(brand)
else:
raise ValueError(f"Unknown type: {vehicle_type}")Код, которому нужны объекты, называется клиентским кодом. Он обращается к фабрике, а не вызывает конструкторы напрямую:
factory = VehicleFactory()
my_car = factory.create_vehicle("car", "Toyota")
my_bike = factory.create_vehicle("bike", "Honda")
print(my_car.info()) # Автомобиль: Toyota
print(my_bike.info()) # Мотоцикл: HondaСделай фабрику более гибкой с помощью *args:
class FlexibleFactory:
def create_vehicle(self, vehicle_type, *args):
if vehicle_type == "car":
return Car(args[0]) # Только марка
elif vehicle_type == "truck":
return Truck(args[0], args[1]) # Марка и грузоподъёмность
else:
raise ValueError(f"Unknown type: {vehicle_type}")
class Truck:
def __init__(self, brand, capacity):
self.brand = brand
self.capacity = capacity
self.type = "Truck"
def info(self):
return f"{self.type}: {self.brand} ({self.capacity}t)"Используй гибкую фабрику:
flexible = FlexibleFactory()
car = flexible.create_vehicle("car", "Ford")
truck = flexible.create_vehicle("truck", "Volvo", "20")
print(car.info()) # Автомобиль: Ford
print(truck.info()) # Грузовик: Volvo (20t)Вывод:
Car: Toyota
Bike: Honda
Car: Ford
Truck: Volvo (20t)Ключевой момент: шаблон «Фабрика» позволяет создавать объекты, не зная их точного класса. Фабричный метод решает, какой класс создать, на основе параметров. Используй *args, чтобы обрабатывать продукты с разными параметрами конструктора. Это делает твой код более гибким и упрощает добавление новых типов продуктов.
Задание
СреднеВ этом задании ты реализуешь систему фабрики фигур, используя правильный объектно-ориентированный подход с наследованием и полиморфизмом.
Заверши реализацию в следующих файлах:
shape.py— базовый класс Shapecircle.py— реализация Circlerectangle.py— реализация Rectangletriangle.py— реализация Triangleshapefactory.py— класс-фабрика для создания фигур
В каждом файле есть подробные комментарии TODO, которые помогут тебе с реализацией. Внимательно следуй этим комментариям, чтобы твой код соответствовал всем требованиям.
Попробуйте сами
from shapefactory import ShapeFactory
from shape import Shape
from circle import Circle
from rectangle import Rectangle
from triangle import Triangle
import sys
# Выполнение тестового случая
test_case = input()
factory = ShapeFactory()
if test_case == "circle_area":
circle = factory.create_shape("circle", 5)
print(f"{circle.area():.2f}")
elif test_case == "rectangle_perimeter":
rectangle = factory.create_shape("rectangle", 4, 6)
print(f"{rectangle.perimeter()}")
elif test_case == "triangle_perimeter":
triangle = factory.create_shape("triangle", 3, 4, 5)
print(f"{triangle.perimeter()}")
elif test_case == "invalid_shape":
try:
factory.create_shape("hexagon", 6)
print("No exception raised")
except ValueError as e:
print(str(e))
elif test_case == "case_insensitive":
circle = factory.create_shape("CiRcLe", 3)
print(f"{circle.area():.2f}")
elif test_case == "shape_inheritance":
shapes = [
factory.create_shape("circle", 2),
factory.create_shape("rectangle", 2, 3),
factory.create_shape("triangle", 3, 4, 5)
]
all_shapes = all(isinstance(shape, Shape) for shape in shapes)
print(all_shapes)
elif test_case == "zero_radius_circle":
circle = factory.create_shape("circle", 0)
print(f"{circle.area():.2f} {circle.perimeter():.2f}")
elif test_case == "negative_dimensions":
rectangle = factory.create_shape("rectangle", -2, -3)
print(f"{rectangle.area()}")
elif test_case == "large_values":
circle = factory.create_shape("circle", 1000000)
print(f"{circle.area():.2e}")
elif test_case == "polymorphism_test":
shapes = [
factory.create_shape("circle", 2),
factory.create_shape("rectangle", 3, 4),
factory.create_shape("triangle", 3, 4, 5)
]
area_sum = sum(shape.area() for shape in shapes)
perimeter_sum = sum(shape.perimeter() for shape in shapes)
print(f"Area sum: {area_sum:.2f}, Perimeter sum: {perimeter_sum:.2f}")
elif test_case == "triangle_area":
triangle = factory.create_shape("triangle", 3, 4, 5)
print(f"{triangle.area():.2f}")
elif test_case == "method_override":
circle = factory.create_shape("circle", 2)
rectangle = factory.create_shape("rectangle", 3, 4)
triangle = factory.create_shape("triangle", 3, 4, 5)
# Получить объекты методов для сравнения реализаций
circle_area = Circle.area
rectangle_area = Rectangle.area
triangle_area = Triangle.area
circle_perimeter = Circle.perimeter
rectangle_perimeter = Rectangle.perimeter
triangle_perimeter = Triangle.perimeter
# Проверить, что все реализации уникальны
unique_areas = len({circle_area, rectangle_area, triangle_area}) == 3
unique_perimeters = len({circle_perimeter, rectangle_perimeter, triangle_perimeter}) == 3
if unique_areas and unique_perimeters:
print("All shapes correctly override methods")
else:
print("Some shapes share method implementations")В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Введение в ООПВнешние файлыКлассы и объектыПараметр selfМетодыАтрибутыМетод-конструктор (__init__)Повторение — простой калькулятор4Наследование
Основы наследованияФункция super()Переопределение методовМножественное наследованиеПорядок разрешения методовПовторение: иерархия сотрудников7Специальные методы
Введение в магические методыПерегрузка операторовМагические методы контейнеровПовторение — пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн «Одиночка»Паттерн «Фабрика»Паттерн «Наблюдатель»Паттерн «Стратегия»2Декораторы
Введение в декораторыДекоратор свойстваДекоратор статического методаДекоратор метода класса5Полиморфизм
Переопределение методов: повторениеУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовПовторение — калькулятор фигур8Продвинутые концепции ООП
Композиция и наследованиеМиксиныСтатические методы и методы классаДекораторы классовМенеджеры контекста11Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»3Свойства классов
Переменные экземпляра и классаДекораторы свойствПриватные атрибутыПовторение — менеджер банковского счёта6Инкапсуляция
Публичные, защищённые и приватные членыМодификаторы доступаСокрытие информацииПродвинутые декораторы свойствПовторение — система учёта студентов12Проект: Система управления библиотекой
Обзор проектаКлассы книг и пользователейСистема выдачи книгФункция поискаИнтерфейс администратораТестирование и интеграцияПотренируйтесь самостоятельно: Онлайн-компилятор Python