Menu
Coddy logo textTech

Zusammenfassung – Formen-Rechner

Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 27 von 64.

challenge icon

Aufgabe

Mittel

In dieser Herausforderung implementieren Sie ein Formberechnungssystem, das Polymorphismus demonstriert.

Implementieren Sie die erforderlichen Klassen in den folgenden Dateien (suchen Sie nach TODO-Kommentaren in jeder Datei):

  • shape.py – Definieren Sie die abstrakte Basisklasse Shape
  • circle.py – Implementieren Sie die Klasse Circle
  • rectangle.py – Implementieren Sie die Klasse Rectangle
  • triangle.py – Implementieren Sie die Klasse Triangle
  • unknownshape.py – Erstellen Sie eine nicht abgeleitete Klasse, die Duck Typing demonstriert
  • shapecalculator.py – Implementieren Sie die Funktionalität des Taschenrechners

Folgen Sie den TODO-Kommentaren in jeder Datei für eine schrittweise Anleitung. Die umfassende Test-Suite wird Ihnen helfen, das erwartete Verhalten zu verstehen und sicherzustellen, dass Ihre Implementierung alle Anforderungen korrekt erfüllt.

Spickzettel

Da keine Lektionsinhalte bereitgestellt wurden, sondern nur Aufgabenanweisungen, kann ich kein Cheatsheet erstellen. Cheatsheets sollten in erster Linie auf der Theorie und den Konzepten der Lektion basieren, wobei Challenge-Inhalte nur dann als Ergänzung dienen, wenn sie zusätzliche nützliche Erklärungen enthalten, die nicht in der Lektion abgedeckt wurden.

Probier es selbst

from circle import Circle
from rectangle import Rectangle
from triangle import Triangle
from unknownshape import UnknownShape
from shapecalculator import ShapeCalculator
import math

# Testfall-Handler
test_case = input()

def test_basic_functionality():
    calculator = ShapeCalculator()
    
    # Test mit Kreis
    circle = Circle(5)
    print(f"Testing {circle}")
    results = calculator.process_shape(circle)
    print(f"Results: {results}")
    print()
    
    # Test mit Rechteck
    rectangle = Rectangle(4, 6)
    print(f"Testing {rectangle}")
    results = calculator.process_shape(rectangle)
    print(f"Results: {results}")
    print()
    
    # Test mit Dreieck
    triangle = Triangle(3, 4, 5)
    print(f"Testing {triangle}")
    results = calculator.process_shape(triangle)
    print(f"Results: {results}")
    print()
    
    # Test mit UnknownShape (Duck-Typing)
    unknown = UnknownShape("Custom", 10)
    print(f"Testing {unknown}")
    results = calculator.process_shape(unknown)
    print(f"Results: {results}")

def test_edge_cases():
    calculator = ShapeCalculator()
    
    # Test mit Nullwerten
    print("Testing zero values:")
    circle = Circle(0)
    print(f"Circle(0) area: {circle.area()}, perimeter: {circle.perimeter()}")
    
    rectangle = Rectangle(0, 5)
    print(f"Rectangle(0, 5) area: {rectangle.area()}, perimeter: {rectangle.perimeter()}")
    
    # Test mit sehr großen Werten
    print("\
Testing large values:")
    large_circle = Circle(1000000)
    print(f"Circle(1000000) area: {large_circle.area():.2e}, perimeter: {large_circle.perimeter():.2e}")
    
    # Test mit Dezimalwerten
    print("\
Testing decimal values:")
    decimal_circle = Circle(0.5)
    print(f"Circle(0.5) area: {decimal_circle.area()}, perimeter: {decimal_circle.perimeter()}")
    
    decimal_triangle = Triangle(2.5, 3.5, 4.5)
    print(f"Triangle(2.5, 3.5, 4.5) area: {decimal_triangle.area()}, perimeter: {decimal_triangle.perimeter()}")

def test_inheritance():
    # Erstelle Instanzen jeder Form
    circle = Circle(5)
    rectangle = Rectangle(4, 6)
    triangle = Triangle(3, 4, 5)
    unknown = UnknownShape("Custom", 10)
    
    # Teste Vererbungsbeziehungen
    from shape import Shape
    print(f"Circle is a Shape: {isinstance(circle, Shape)}")
    print(f"Rectangle is a Shape: {isinstance(rectangle, Shape)}")
    print(f"Triangle is a Shape: {isinstance(triangle, Shape)}")
    print(f"UnknownShape is a Shape: {isinstance(unknown, Shape)}")
    
    # Teste Verfügbarkeit der Methoden
    print("\
Method availability:")
    for shape_name, shape_obj in [("Circle", circle), ("Rectangle", rectangle), 
                                ("Triangle", triangle), ("UnknownShape", unknown)]:
        print(f"{shape_name} has area(): {hasattr(shape_obj, 'area')}")
        print(f"{shape_name} has perimeter(): {hasattr(shape_obj, 'perimeter')}")
        print(f"{shape_name} has describe(): {hasattr(shape_obj, 'describe')}")

def test_polymorphism():
    calculator = ShapeCalculator()
    
    # Erstelle eine Liste verschiedener Formen
    shapes = [
        Circle(5),
        Rectangle(4, 6),
        Triangle(3, 4, 5),
        UnknownShape("Custom", 10)
    ]
    
    print("Testing polymorphic behavior:")
    for i, shape in enumerate(shapes, 1):
        print(f"\
Shape {i}: {shape.__class__.__name__}")
        results = calculator.process_shape(shape)
        print(f"Results: {results}")

def test_duck_typing():
    calculator = ShapeCalculator()
    
    # Erstelle eine komplett neue Klasse, die die erforderlichen Methoden besitzt
    class CustomDuckShape:
        def __init__(self, name, factor):
            self.name = name
            self.factor = factor
        
        def area(self):
            return self.factor * 3
        
        def perimeter(self):
            return self.factor * 12
        
        def describe(self):
            return f"This is a {self.name} duck-typed shape with area {self.area()} and perimeter {self.perimeter()}"
        
        def __str__(self):
            return f"Custom {self.name} with factor {self.factor}"
    
    # Test mit der benutzerdefinierten Duck-Typing-Form
    duck_shape = CustomDuckShape("DuckTyped", 5)
    print(f"Testing duck typing with: {duck_shape}")
    results = calculator.process_shape(duck_shape)
    print(f"Results: {results}")
    
    # Vergleich mit einer regulären Form
    circle = Circle(5)
    print(f"\
Comparing with regular shape: {circle}")
    results = calculator.process_shape(circle)
    print(f"Results: {results}")

def test_invalid_inputs():
    calculator = ShapeCalculator()
    
    try:
        # Test mit negativem Radius
        print("Testing Circle with negative radius:")
        negative_circle = Circle(-5)
        results = calculator.process_shape(negative_circle)
        print(f"Results: {results}")
    except Exception as e:
        print(f"Error with negative circle: {e}")
    
    try:
        # Test mit ungültigem Dreieck (Seiten, die kein Dreieck bilden können)
        print("\
Testing invalid Triangle (1, 1, 10):")
        invalid_triangle = Triangle(1, 1, 10)  # Verletzt die Dreiecksungleichung
        results = calculator.process_shape(invalid_triangle)
        print(f"Results: {results}")
        # Prüfen, ob die Flächenberechnung ein gültiges Ergebnis liefert
        area = invalid_triangle.area()
        if math.isnan(area) or not isinstance(area, float) or area <= 0:
            print(f"Invalid triangle area: {area}")
    except Exception as e:
        print(f"Error with invalid triangle: {e}")

# Führe den entsprechenden Test basierend auf der Eingabe aus
if test_case == "basic_functionality":
    test_basic_functionality()
elif test_case == "edge_cases":
    test_edge_cases()
elif test_case == "inheritance":
    test_inheritance()
elif test_case == "polymorphism":
    test_polymorphism()
elif test_case == "duck_typing":
    test_duck_typing()
elif test_case == "invalid_inputs":
    test_invalid_inputs()
else:
    # Standard-Testfall
    test_basic_functionality()

Alle Lektionen in Object Oriented Programming