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, abstractmethodCrea un'interfaccia con solo metodi astratti:
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passTutti 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 10x8Puoi 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 circlePunto 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.
Sfida
MedioIn 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 Songvideo.py- Implementa la classe Videomediaplayer.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!")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
1Fondamenti di OOP
File esterniIntroduzione a OOPClassi vs. oggettiIl parametro selfMetodiAttributiMetodo costruttore (__init__)Riepilogo - Calcolatrice semplice4Ereditarietà
Ereditarietà di baseLa funzione super()Sovrascrittura dei metodiEreditarietà multiplaOrdine di risoluzione dei metodiRiepilogo - Gerarchia dei dipendenti7Metodi speciali
Introduzione ai metodi magiciSovraccarico degli operatoriMetodi magici dei contenitoriRiepilogo - Lista personalizzata10Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello ObserverModello Strategy2Decoratori
Introduzione ai decoratoriDecoratore di proprietàDecoratore di metodo staticoDecoratore di metodo di classe5Polimorfismo
Ripasso dell'override dei metodiDuck typingClassi e metodi astrattiProgettazione delle interfacceRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàMixinMetodi statici e di classeDecorator di classeContext manager11Pattern di progettazione - Parte 2
Pattern dei comandiPattern adattatorePattern decoratorePattern metodo templatePattern statoPattern composito3Proprietà delle classi
Variabili di istanza e di classeDecorator delle proprietàAttributi privatiRiepilogo - Gestore di conti bancari6Incapsulamento
Membri pubblici, protetti e privatiModificatori di accessoOccultamento delle informazioniDecorator delle proprietà: avanzatiRipasso - Sistema di registri degli studenti12Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e UtenteSistema di prestitoFunzionalità di ricercaInterfaccia amministratoreTest e integrazioneEsercitati da solo: Compilatore Python online