Menu
Coddy logo textTech

Wzorzec Factory

Część sekcji Programowanie obiektowe ścieżki Python w Coddy. Lekcja 46 z 64.

Wzorzec Fabryki tworzy obiekty bez określania ich dokładnej klasy. Zamiast bezpośrednio wywoływać konstruktory, używasz metody fabrykującej, która decyduje, którą klasę utworzyć.

Oto proste klasy produktów:

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}"

Utwórz klasę fabryki, aby tworzyć te obiekty:

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}")

Użyj fabryki zamiast wywoływać konstruktory bezpośrednio:

factory = VehicleFactory()
my_car = factory.create_vehicle("car", "Toyota")
my_bike = factory.create_vehicle("bike", "Honda")

print(my_car.info())   # Samochód: Toyota
print(my_bike.info())  # Motocykl: Honda

Uczyń fabrykę bardziej elastyczną, używając *args:

class FlexibleFactory:
    def create_vehicle(self, vehicle_type, *args):
        if vehicle_type == "car":
            return Car(args[0])  # Tylko marka
        elif vehicle_type == "truck":
            return Truck(args[0], args[1])  # Marka i ładowność
        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)"

Użyj elastycznej fabryki:

flexible = FlexibleFactory()
car = flexible.create_vehicle("car", "Ford")
truck = flexible.create_vehicle("truck", "Volvo", "20")

print(car.info())    # Samochód: Ford
print(truck.info())  # Ciężarówka: Volvo (20t)

Wynik:

Car: Toyota
Bike: Honda
Car: Ford
Truck: Volvo (20t)

Kluczowa kwestia: Wzorzec Fabryki pozwala tworzyć obiekty bez znajomości ich dokładnej klasy. Metoda fabrykująca decyduje na podstawie parametrów, którą klasę utworzyć. Użyj *args, aby obsługiwać produkty z różnymi parametrami konstruktora. Dzięki temu Twój kod jest bardziej elastyczny i łatwiej rozszerzyć go o nowe typy produktów.

challenge icon

Wyzwanie

Średni

W tym wyzwaniu zaimplementujesz system fabryki figur geometrycznych, stosując właściwy projekt obiektowy z dziedziczeniem i polimorfizmem.

Uzupełnij implementację w następujących plikach:

  • shape.py - bazowa klasa Shape
  • circle.py - implementacja Circle
  • rectangle.py - implementacja Rectangle
  • triangle.py - implementacja Triangle
  • shapefactory.py - klasa fabryki do tworzenia figur

Każdy plik zawiera szczegółowe komentarze TODO, które pomogą Ci w implementacji. Uważnie postępuj zgodnie z tymi komentarzami, aby mieć pewność, że Twój kod spełnia wszystkie wymagania.

Spróbuj swoich sił

from shapefactory import ShapeFactory
from shape import Shape
from circle import Circle
from rectangle import Rectangle
from triangle import Triangle
import sys

# Wykonywanie przypadków testowych
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)
    
    # Pobierz obiekty metod, aby porównać implementacje
    circle_area = Circle.area
    rectangle_area = Rectangle.area
    triangle_area = Triangle.area
    
    circle_perimeter = Circle.perimeter
    rectangle_perimeter = Rectangle.perimeter
    triangle_perimeter = Triangle.perimeter
    
    # Sprawdź, czy wszystkie implementacje są unikalne
    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")
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Python online