Conception d'interfaces
Fait partie de la section Programmation orientée objet du Journey Python de Coddy. Leçon 26 sur 64.
Une interface définit un contrat que les classes doivent respecter. En Python, nous créons des interfaces à l’aide de classes de base abstraites dont toutes les méthodes sont abstraites.
Importez le module abc :
from abc import ABC, abstractmethodCréez une interface avec uniquement des méthodes abstraites :
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passToutes les méthodes d’une interface devraient être abstraites : elles définissent ce que les classes qui les implémentent doivent faire, et non comment le faire.
Implémentez l’interface dans une classe concrète :
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}"Créez une autre classe qui implémente la même interface :
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}"Utilisez l’interface de manière polymorphe :
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
print(shape.draw())
print(shape.resize(10, 8))Sortie :
Drawing a circle
Resized circle to radius 4.0
Drawing a rectangle
Resized rectangle to 10x8Vous pouvez également utiliser des interfaces comme annotations de type :
def render_shape(drawable: Drawable):
return drawable.draw()
circle = Circle(3)
print(render_shape(circle))Sortie :
Drawing a circlePoint clé : les interfaces définissent ce que les classes doivent faire, et non comment elles le font. Utilisez des classes de base abstraites contenant uniquement des méthodes abstraites pour créer des contrats clairs que les classes qui les implémentent doivent respecter. Cela garantit un comportement cohérent entre différentes implémentations.
Défi
MoyenDans ce défi, vous allez implémenter un système de lecteur multimédia avec des interfaces.
Vous devez modifier les fichiers suivants :
playable.py- Implémenter les classes de base abstraites (interfaces)song.py- Implémenter la classe Songvideo.py- Implémenter la classe Videomediaplayer.py- Implémenter la classe MediaPlayer
Chaque fichier contient des commentaires TODO détaillés pour vous guider dans votre implémentation. Suivez ces commentaires pour créer un système de lecteur multimédia complet avec un héritage approprié et une implémentation des interfaces.
Essayez vous-même
from song import Song
from video import Video
from mediaplayer import MediaPlayer
from playable import Playable, MediaInfo
# Gestionnaire complet de cas de test
test_case = input()
if test_case == "default_test":
# Cas de test par défaut du problème original
song = Song("Bohemian Rhapsody", "Queen", 355)
video = Video("Python Tutorial", "1080p", 1800)
player = MediaPlayer()
# Test avec une chanson
player.set_media(song)
print(player.current_media.get_info())
print(player.play())
print(player.pause())
print(player.stop())
print() # Ligne vide pour la lisibilité
# Test avec une vidéo
player.set_media(video)
print(player.current_media.get_info())
print(player.play())
print(player.pause())
print(player.stop())
elif test_case == "empty_player":
# Tester le lecteur multimédia sans média défini
player = MediaPlayer()
print(player.play()) # Should print "No media set"
print(player.pause()) # Should print "No media set"
print(player.stop()) # Should print "No media set"
elif test_case == "time_formatting":
# Tester le formatage du temps dans la méthode 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":
# Vérifier que Song et Video implémentent correctement les interfaces
song = Song("Test Song", "Test Artist", 180)
video = Video("Test Video", "480p", 240)
# Vérifier l'implémentation de l'interface
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)}")
# Tester toutes les méthodes de l'interface
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":
# Tester le comportement polymorphe avec une liste de différents types de médias
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":
# Tester les cas limites
empty_song = Song("", "", 0)
edge_video = Video("A" * 100, "", -10) # Titre très long, résolution vide, durée négative
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":
# Implémenter un test de stress avec de nombreux objets média
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()
# Tester avec toutes les chansons
for i, song in enumerate(songs):
player.set_media(song)
if i % 10 == 0: # Afficher uniquement tous les 10 pour éviter trop de sortie
print(f"Playing song {i+1}: {player.play()}")
# Tester avec toutes les vidéos
for i, video in enumerate(videos):
player.set_media(video)
if i % 10 == 0: # Afficher uniquement tous les 10 pour éviter trop de sortie
print(f"Playing video {i+1}: {player.play()}")
print("Stress test completed successfully!")Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Les fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe paramètre selfMéthodesAttributsMéthode constructeur (__init__)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLa fonction super()Redéfinition de méthodeHéritage multipleOrdre de résolution des méthodesRécapitulatif - Hiérarchie des employés7Méthodes spéciales
Introduction aux méthodes magiquesSurcharge d'opérateursMéthodes magiques de conteneurRécapitulatif - Liste personnalisée10Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FactoryPatron ObserverPatron Strategy2Décorateurs
Introduction aux décorateursDécorateur de propriétéDécorateur de méthode statiqueDécorateur de méthode de classe5Polymorphisme
Retour sur la redéfinition de méthodeDuck TypingClasses et méthodes abstraitesConception d'interfacesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageMixinsMéthodes statiques et de classeDécorateurs de classeGestionnaires de contexte11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Propriétés de classe
Variables d'instance vs variables de classeDécorateurs de propriétéAttributs privésRécapitulatif - Gestionnaire de compte bancaireEntraînez-vous par vous-même : Compilateur Python en ligne