Komposition vs. Vererbung
Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 37 von 64.
Die objektorientierte Programmierung bietet zwei Hauptansätze für die Wiederverwendung von Code: Vererbung („ist-ein“-Beziehung) und Komposition („hat-ein“-Beziehung).
Hier ist ein Beispiel für Vererbung, die eine „ist-ein“-Beziehung erstellt:
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
return f"{self.name} is eating"
class Dog(Animal): # Dog „ist ein“ Animal
def bark(self):
return "Woof!"
dog = Dog("Buddy")
print(dog.eat()) # Geerbte Methode
print(dog.bark()) # Eigene MethodeHier ist ein Beispiel für Komposition, die eine „hat-ein“-Beziehung (has-a) erstellt:
class Engine:
def start(self):
return "Engine started"
def stop(self):
return "Engine stopped"
class Car: # Auto „hat einen“ Motor
def __init__(self):
self.engine = Engine() # Komposition
def start(self):
return self.engine.start()
car = Car()
print(car.start()) # Verwendet den zusammengesetzten MotorVergleichen Sie beide Ansätze mit einem komplexeren Beispiel:
# Vererbungsansatz
class Bird:
def move(self):
return "Flying"
class Duck(Bird):
def quack(self):
return "Quack!"
# Kompositionsansatz
class FlyBehavior:
def move(self):
return "Flying"
class SwimBehavior:
def move(self):
return "Swimming"
class VersatileDuck:
def __init__(self):
self.fly_behavior = FlyBehavior()
self.swim_behavior = SwimBehavior()
def fly(self):
return self.fly_behavior.move()
def swim(self):
return self.swim_behavior.move()
def quack(self):
return "Quack!"Testen Sie beide Ansätze:
# Vererbung
duck1 = Duck()
print(duck1.move()) # Fliegen
print(duck1.quack()) # Quack!
# Komposition
duck2 = VersatileDuck()
print(duck2.fly()) # Fliegen
print(duck2.swim()) # Schwimmen
print(duck2.quack()) # Quack!Ausgabe:
Buddy is eating
Woof!
Engine started
Flying
Quack!
Flying
Swimming
Quack!Wesentliche Unterschiede:
Vererbung:
- Starke Kopplung zwischen Eltern- und Kindklasse
- „Ist-ein“-Beziehung
- Änderungen an der Elternklasse wirken sich auf alle Kindklassen aus
- Am besten für echte hierarchische Beziehungen geeignet
Komposition:
- Lose Kopplung zwischen Objekten
- „Hat-eine“-Beziehung
- Flexibler – kann das Verhalten zur Laufzeit ändern
- Einfacher zu testen und zu modifizieren
Kernpunkt: Verwenden Sie Vererbung, wenn eine echte „is-a“-Beziehung besteht. Verwenden Sie Komposition, wenn Sie Flexibilität und lose Kopplung benötigen. Das Prinzip „composition over inheritance“ legt nahe, in den meisten Fällen die Komposition zu bevorzugen, da sie flexibler und wartungsfreundlicher ist.
Aufgabe
MittelIn dieser Challenge implementierst du ein Medienbibliothekssystem unter Verwendung von Vererbungs- und Kompositionsmustern.
Du musst die folgenden Dateien bearbeiten und dabei den TODO-Kommentaren in jeder Datei folgen:
media.py,book.py,movie.py,musicalbum.py- Für die Vererbungsimplementierungmediaitem.py,bookcomposition.py,moviecomposition.py,musicalbumcomposition.py- Für die Kompositionsimplementierung
Jeder Medientyp sollte Folgendes haben:
- Attribute für Titel, Ersteller (Autor/Regisseur/Künstler) und Jahr
- Eine entsprechende
display_info()Methode
Spickzettel
Objektorientierte Programmierung bietet zwei Hauptansätze für die Wiederverwendung von Code: Vererbung („ist-ein“-Beziehung) und Komposition („hat-ein“-Beziehung).
Beispiel für Vererbung:
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
return f"{self.name} is eating"
class Dog(Animal): # Dog "ist ein" Animal
def bark(self):
return "Woof!"
dog = Dog("Buddy")
print(dog.eat()) # Vererbte Methode
print(dog.bark()) # Eigene MethodeBeispiel für Komposition:
class Engine:
def start(self):
return "Engine started"
class Car: # Car "hat einen" Engine
def __init__(self):
self.engine = Engine() # Komposition
def start(self):
return self.engine.start()
car = Car()
print(car.start()) # Verwendet komponierte EngineWesentliche Unterschiede:
Vererbung:
- Starke Kopplung zwischen Eltern- und Kindklasse
- „Ist-ein“-Beziehung
- Änderungen an der Elternklasse wirken sich auf alle Kindklassen aus
- Am besten für echte hierarchische Beziehungen geeignet
Komposition:
- Lose Kopplung zwischen Objekten
- „Hat-ein“-Beziehung
- Flexibler – Verhalten kann zur Laufzeit geändert werden
- Einfacher zu testen und zu modifizieren
Verwenden Sie Vererbung für echte „ist-ein“-Beziehungen. Verwenden Sie Komposition für Flexibilität und lose Kopplung. Das Prinzip „Komposition statt Vererbung“ legt nahe, Komposition in den meisten Fällen zu bevorzugen.
Probier es selbst
from media import Media
from book import Book
from movie import Movie
from musicalbum import MusicAlbum
from mediaitem import MediaItem
from bookcomposition import BookComposition
from moviecomposition import MovieComposition
from musicalbumcomposition import MusicAlbumComposition
# Umfassender Testfall-Handler
test_case = input()
def test_inheritance_basic():
book = Book("The Hobbit", "J.R.R. Tolkien", 1937)
movie = Movie("The Matrix", "Wachowski Sisters", 1999)
album = MusicAlbum("Abbey Road", "The Beatles", 1969)
assert book.display_info() == "Book: The Hobbit by J.R.R. Tolkien (1937)"
assert movie.display_info() == "Movie: The Matrix directed by Wachowski Sisters (1999)"
assert album.display_info() == "Music Album: Abbey Road by The Beatles (1969)"
def test_composition_basic():
book_comp = BookComposition("Dune", "Frank Herbert", 1965)
movie_comp = MovieComposition("Inception", "Christopher Nolan", 2010)
album_comp = MusicAlbumComposition("Thriller", "Michael Jackson", 1982)
assert book_comp.display_info() == "Book: Dune by Frank Herbert (1965)"
assert movie_comp.display_info() == "Movie: Inception directed by Christopher Nolan (2010)"
assert album_comp.display_info() == "Music Album: Thriller by Michael Jackson (1982)"
def test_inheritance_relationships():
book = Book("Test Book", "Test Author", 2000)
movie = Movie("Test Movie", "Test Director", 2001)
album = MusicAlbum("Test Album", "Test Artist", 2002)
assert isinstance(book, Book)
assert isinstance(book, Media)
assert isinstance(movie, Movie)
assert isinstance(movie, Media)
assert isinstance(album, MusicAlbum)
assert isinstance(album, Media)
def test_attribute_access():
# Teste Vererbungsansatz
book = Book("Test Book", "Test Author", 2000)
assert book.title == "Test Book"
assert book.creator == "Test Author"
assert book.year == 2000
# Teste Kompositionsansatz
book_comp = BookComposition("Test Book", "Test Author", 2000)
assert book_comp.media.title == "Test Book"
assert book_comp.media.creator == "Test Author"
assert book_comp.media.year == 2000
def test_polymorphism():
media_list = [
Book("Book1", "Author1", 2001),
Movie("Movie1", "Director1", 2002),
MusicAlbum("Album1", "Artist1", 2003)
]
assert media_list[0].display_info() == "Book: Book1 by Author1 (2001)"
assert media_list[1].display_info() == "Movie: Movie1 directed by Director1 (2002)"
assert media_list[2].display_info() == "Music Album: Album1 by Artist1 (2003)"
def test_edge_cases():
# Leere Zeichenfolgen
book = Book("", "", 0)
assert book.display_info() == "Book: by (0)"
# Sonderzeichen - Syntaxfehler hier korrigiert
movie = Movie("Test\"Movie", "Test\\nDirector", -1)
assert movie.display_info() == "Movie: Test\"Movie directed by Test\\nDirector (-1)"
# Extreme Jahreszahlen
album = MusicAlbum("Test Album", "Test Artist", 9999)
assert album.display_info() == "Music Album: Test Album by Test Artist (9999)"
def test_stress():
# Erstelle viele Medienobjekte
books = [Book(f"Book{i}", f"Author{i}", 2000+i) for i in range(100)]
movies = [Movie(f"Movie{i}", f"Director{i}", 2000+i) for i in range(100)]
albums = [MusicAlbum(f"Album{i}", f"Artist{i}", 2000+i) for i in range(100)]
for i, book in enumerate(books):
assert book.display_info() == f"Book: Book{i} by Author{i} ({2000+i})"
for i, movie in enumerate(movies):
assert movie.display_info() == f"Movie: Movie{i} directed by Director{i} ({2000+i})"
for i, album in enumerate(albums):
assert album.display_info() == f"Music Album: Album{i} by Artist{i} ({2000+i})"
# Führe den entsprechenden Test basierend auf der Eingabe aus
if test_case == "default_test" or test_case == "":
test_inheritance_basic()
test_composition_basic()
print("All tests passed!")
elif test_case == "inheritance_test":
test_inheritance_basic()
test_inheritance_relationships()
print("Inheritance tests passed!")
elif test_case == "composition_test":
test_composition_basic()
print("Composition tests passed!")
elif test_case == "polymorphism_test":
test_polymorphism()
print("Polymorphism tests passed!")
elif test_case == "attribute_test":
test_attribute_access()
print("Attribute tests passed!")
elif test_case == "edge_cases":
test_edge_cases()
print("Edge case tests passed!")
elif test_case == "stress_test":
test_stress()
print("Stress tests passed!")Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktor-Methode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDie super()-FunktionMethoden überschreibenMehrfachvererbungMethod Resolution OrderZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden
Einführung in Magic MethodsOperator-ÜberladungMagic Methods für ContainerRückblick - Eigene Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung2Dekoratoren
Einführung in DekoratorenProperty-DekoratorStatischer Methoden-DekoratorKlassenmethoden-Dekorator5Polymorphismus
Methoden-Überschreiben vertieftDuck TypingAbstrakte Klassen und MethodenInterface-DesignZusammenfassung – Formen-Rechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische und KlassenmethodenKlassendekoratorenContext Manager3Klasseneigenschaften
Instanz- vs. KlassenvariablenProperty-DekoratorenPrivate AttributeZusammenfassung – Bankkonto-Manager6Kapselung
Public, Protected, Private MemberZugriffsmodifikatorenInformation HidingProperty-Decorators für FortgeschritteneZusammenfassung - Studentenverwaltungssystem12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen