Menu
Coddy logo textTech

Composizione vs ereditarietà

Fa parte della sezione Programmazione orientata agli oggetti del percorso Python di Coddy. Lezione 37 di 64.

La programmazione orientata agli oggetti offre due approcci principali al riutilizzo del codice: l’ereditarietà (relazione «è un») e la composizione (relazione «ha un»).

Ecco un esempio di ereditarietà che crea una relazione «è un»:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def eat(self):
        return f"{self.name} is eating"

class Dog(Animal):  # Dog "is an" Animal
    def bark(self):
        return "Woof!"

dog = Dog("Buddy")
print(dog.eat())   # Metodo ereditato
print(dog.bark())  # Metodo proprio

Ecco un esempio di composizione che crea una relazione «ha un»:

class Engine:
    def start(self):
        return "Engine started"
    
    def stop(self):
        return "Engine stopped"

class Car:  # Car "has an" Engine
    def __init__(self):
        self.engine = Engine()  # Composizione
    
    def start(self):
        return self.engine.start()

car = Car()
print(car.start())  # Usa il motore composto

Confronta entrambi gli approcci con un esempio più complesso:

# Approccio basato sull'ereditarietà
class Bird:
    def move(self):
        return "Flying"

class Duck(Bird):
    def quack(self):
        return "Quack!"

# Approccio basato sulla composizione
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!"

Prova entrambi gli approcci:

# Ereditarietà
duck1 = Duck()
print(duck1.move())  # Volando
print(duck1.quack()) # Qua!

# Composizione  
duck2 = VersatileDuck()
print(duck2.fly())   # Volando
print(duck2.swim())  # Nuotando
print(duck2.quack()) # Qua!

Output:

Buddy is eating
Woof!
Engine started
Flying
Quack!
Flying
Swimming
Quack!

Differenze principali:

Ereditarietà:

  • Forte accoppiamento tra genitore e figlio
  • Relazione "è un"
  • Le modifiche al genitore influiscono su tutti i figli
  • Ideale per relazioni gerarchiche effettive

Composizione:

  • Accoppiamento debole tra oggetti
  • Relazione "ha-un"
  • Più flessibile: può cambiare comportamento durante l'esecuzione
  • Più facile da testare e modificare

Punto chiave: usa l’ereditarietà quando c’è una vera relazione «è un». Usa la composizione quando hai bisogno di flessibilità e di un accoppiamento debole. Il principio «composizione invece di ereditarietà» suggerisce di preferire la composizione nella maggior parte dei casi, grazie alla sua flessibilità e manutenibilità.

challenge icon

Sfida

Medio

In questa sfida, implementerai un sistema di libreria multimediale usando sia i modelli di ereditarietà che di composizione.

Devi modificare i seguenti file, seguendo i commenti TODO all'interno di ciascuno:

  • media.py, book.py, movie.py, musicalbum.py - Per l'implementazione dell'ereditarietà
  • mediaitem.py, bookcomposition.py, moviecomposition.py, musicalbumcomposition.py - Per l'implementazione della composizione

Ogni tipo di media deve avere:

  • Attributi titolo, creatore (autore/regista/artista) e anno
  • Un metodo display_info() appropriato

Provalo tu

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

# Gestore completo dei casi di test
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():
    # Verifica l'approccio basato sull'ereditarietà
    book = Book("Test Book", "Test Author", 2000)
    assert book.title == "Test Book"
    assert book.creator == "Test Author"
    assert book.year == 2000
    
    # Verifica l'approccio basato sulla composizione
    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():
    # Stringhe vuote
    book = Book("", "", 0)
    assert book.display_info() == "Book:  by  (0)"
    
    # Caratteri speciali - errore di sintassi corretto qui
    movie = Movie("Test\"Movie", "Test\\nDirector", -1)
    assert movie.display_info() == "Movie: Test\"Movie directed by Test\\nDirector (-1)"
    
    # Anni estremi
    album = MusicAlbum("Test Album", "Test Artist", 9999)
    assert album.display_info() == "Music Album: Test Album by Test Artist (9999)"

def test_stress():
    # Crea molti oggetti multimediali
    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})"

# Esegui il test appropriato in base all'input
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!")
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Python online