Menu
Coddy logo textTech

Progettazione delle interfacce

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

Un'interfaccia definisce un contratto che le classi devono rispettare. In Python, creiamo interfacce usando classi base astratte in cui tutti i metodi sono astratti.

Importa il modulo abc:

from abc import ABC, abstractmethod

Crea un'interfaccia con solo metodi astratti:

class Drawable(ABC):
    @abstractmethod
    def draw(self):
        pass
    @abstractmethod
    def resize(self, width, height):
        pass

Tutti i metodi in un'interfaccia dovrebbero essere astratti: definiscono cosa devono fare le classi che la implementano, non come farlo.

Implementa l'interfaccia in una classe concreta:

class Circle(Drawable):
    def __init__(self, radius):
        self.radius = radius
    def draw(self):
        return "Drawing a circle"
    def resize(self, width, height):
        self.radius = min(width, height) / 2
        return f"Resized circle to radius {self.radius}"

Crea un'altra classe che implementi la stessa interfaccia:

class Rectangle(Drawable):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def draw(self):
        return "Drawing a rectangle"
    def resize(self, width, height):
        self.width = width
        self.height = height
        return f"Resized rectangle to {width}x{height}"

Usa l'interfaccia in modo polimorfico:

shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
    print(shape.draw())
    print(shape.resize(10, 8))

Output:

Drawing a circle
Resized circle to radius 4.0
Drawing a rectangle
Resized rectangle to 10x8

Puoi anche usare le interfacce come suggerimenti di tipo:

def render_shape(drawable: Drawable):
    return drawable.draw()
circle = Circle(3)
print(render_shape(circle))

Output:

Drawing a circle

Punto chiave: le interfacce definiscono cosa devono fare le classi, non come devono farlo. Usa classi base astratte con solo metodi astratti per creare contratti chiari che le classi che li implementano devono rispettare. Questo garantisce un comportamento coerente tra diverse implementazioni.

challenge icon

Sfida

Medio

In questa sfida implementerai un sistema di riproduzione multimediale con interfacce.

Devi modificare i seguenti file:

  • playable.py - Implementa le classi base astratte (interfacce)
  • song.py - Implementa la classe Song
  • video.py - Implementa la classe Video
  • mediaplayer.py - Implementa la classe MediaPlayer

Ogni file contiene commenti TODO dettagliati che ti guideranno nell'implementazione. Segui questi commenti per creare un sistema di riproduzione multimediale completo con la corretta ereditarietà e implementazione delle interfacce.

Provalo tu

from song import Song
from video import Video
from mediaplayer import MediaPlayer
from playable import Playable, MediaInfo

# Gestore completo dei casi di test
test_case = input()

if test_case == "default_test":
    # Caso di test predefinito del problema originale
    song = Song("Bohemian Rhapsody", "Queen", 355)
    video = Video("Python Tutorial", "1080p", 1800)
    player = MediaPlayer()

    # Test con una canzone
    player.set_media(song)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())
    print()  # Riga vuota per migliorare la leggibilità

    # Test con un video
    player.set_media(video)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())

elif test_case == "empty_player":
    # Test del lettore multimediale senza alcun contenuto impostato
    player = MediaPlayer()
    print(player.play())  # Dovrebbe stampare "No media set"
    print(player.pause())  # Dovrebbe stampare "No media set"
    print(player.stop())  # Dovrebbe stampare "No media set"

elif test_case == "time_formatting":
    # Test della formattazione del tempo nel metodo get_info()
    song1 = Song("Short Song", "Artist A", 65)  # 1:05
    song2 = Song("Long Song", "Artist B", 3661)  # 61:01
    video1 = Video("Hour Video", "720p", 3600)  # 60:00
    
    print(song1.get_info())
    print(song2.get_info())
    print(video1.get_info())

elif test_case == "interface_compliance":
    # Verifica che Song e Video implementino correttamente le interfacce
    song = Song("Test Song", "Test Artist", 180)
    video = Video("Test Video", "480p", 240)
    
    # Verifica dell'implementazione delle interfacce
    print(f"Song implements Playable: {isinstance(song, Playable)}")
    print(f"Song implements MediaInfo: {isinstance(song, MediaInfo)}")
    print(f"Video implements Playable: {isinstance(video, Playable)}")
    print(f"Video implements MediaInfo: {isinstance(video, MediaInfo)}")
    
    # Test di tutti i metodi delle interfacce
    print(song.play())
    print(song.pause())
    print(song.stop())
    print(song.get_title())
    print(song.get_duration())
    print(song.get_info())
    
    print(video.play())
    print(video.pause())
    print(video.stop())
    print(video.get_title())
    print(video.get_duration())
    print(video.get_info())

elif test_case == "polymorphism":
    # Test del comportamento polimorfico con un elenco di diversi tipi di contenuti multimediali
    media_list = [
        Song("Song 1", "Artist 1", 180),
        Video("Video 1", "720p", 300),
        Song("Song 2", "Artist 2", 240),
        Video("Video 2", "1080p", 420)
    ]
    
    player = MediaPlayer()
    
    for media in media_list:
        player.set_media(media)
        print(f"Media: {media.get_title()}")
        print(f"Info: {media.get_info()}")
        print(f"Play: {player.play()}")
        print()

elif test_case == "edge_cases":
    # Verifica i casi limite
    empty_song = Song("", "", 0)
    edge_video = Video("A" * 100, "", -10)  # Titolo molto lungo, risoluzione vuota, durata negativa
    
    print(f"Empty song info: {empty_song.get_info()}")
    print(f"Edge video info: {edge_video.get_info()}")
    
    player = MediaPlayer()
    player.set_media(empty_song)
    print(player.play())
    player.set_media(edge_video)
    print(player.play())

elif test_case == "stress_test":
    # Implementa uno stress test con molti oggetti multimediali
    songs = [Song(f"Song {i}", f"Artist {i}", i * 30) for i in range(1, 101)]
    videos = [Video(f"Video {i}", f"{i*10}p", i * 60) for i in range(1, 101)]
    
    player = MediaPlayer()
    
    # Esegui il test con tutte le canzoni
    for i, song in enumerate(songs):
        player.set_media(song)
        if i % 10 == 0:  # Stampa solo un elemento ogni 10 per evitare un output eccessivo
            print(f"Playing song {i+1}: {player.play()}")
    
    # Esegui il test con tutti i video
    for i, video in enumerate(videos):
        player.set_media(video)
        if i % 10 == 0:  # Stampa solo un elemento ogni 10 per evitare un output eccessivo
            print(f"Playing video {i+1}: {player.play()}")
    
    print("Stress test completed successfully!")
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