Menu
CoddyTech

Factory-Muster

Teil des Abschnitts Objektorientierte Programmierung der Python-Journey von Coddy. Lektion 46 von 64.

Das Factory-Muster erstellt Objekte, ohne ihre genaue Klasse anzugeben. Anstatt Konstruktoren direkt aufzurufen, verwendest du eine Factory-Methode, die entscheidet, welche Klasse instanziiert wird.

Hier sind einfache Produktklassen:

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

Erstelle eine Fabrikklasse, um diese Objekte zu erzeugen:

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

Der Code, der die Objekte benötigt, wird Client-Code genannt. Er fragt die Factory, statt die Konstruktoren direkt aufzurufen:

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

print(my_car.info())   # Auto: Toyota
print(my_bike.info())  # Motorrad: Honda

Gestalte die Fabrik mit *args flexibler:

class FlexibleFactory:
    def create_vehicle(self, vehicle_type, *args):
        if vehicle_type == "car":
            return Car(args[0])  # Nur die Marke
        elif vehicle_type == "truck":
            return Truck(args[0], args[1])  # Marke und Ladekapazität
        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)"

Verwende die flexible Factory:

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

print(car.info())    # Car: Ford
print(truck.info())  # Truck: Volvo (20t)

Ausgabe:

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

Wichtiger Punkt: Mit dem Factory Pattern kannst du Objekte erstellen, ohne ihre genaue Klasse zu kennen. Die Factory-Methode entscheidet anhand von Parametern, welche Klasse instanziiert wird. Verwende *args, um Produkte mit unterschiedlichen Konstruktorparametern zu behandeln. Dadurch wird dein Code flexibler und lässt sich leichter um neue Produkttypen erweitern.

challenge icon

Aufgabe

Mittel

In dieser Herausforderung implementierst du ein Formfabriksystem mit einem geeigneten objektorientierten Design unter Verwendung von Vererbung und Polymorphismus.

Vervollständige die Implementierung in den folgenden Dateien:

  • shape.py - Basisklasse Shape
  • circle.py - Circle-Implementierung
  • rectangle.py - Rectangle-Implementierung
  • triangle.py - Triangle-Implementierung
  • shapefactory.py - Fabrikklasse zum Erstellen von Formen

Jede Datei enthält ausführliche TODO-Kommentare, die dich bei der Implementierung unterstützen. Befolge diese Kommentare sorgfältig, damit dein Code alle Anforderungen erfüllt.

Probier es selbst

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

# Testfall-Ausführung
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)
    
    # Methodenobjekte abrufen, um Implementierungen zu vergleichen
    circle_area = Circle.area
    rectangle_area = Rectangle.area
    triangle_area = Triangle.area
    
    circle_perimeter = Circle.perimeter
    rectangle_perimeter = Rectangle.perimeter
    triangle_perimeter = Triangle.perimeter
    
    # Prüfen, ob alle Implementierungen eindeutig sind
    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 iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Python-Compiler