Conception d'interfaces
Fait partie de la section Object Oriented Programming du Journey Python de Coddy — leçon 26 sur 64.
Une interface définit un contrat que les classes doivent suivre. En Python, nous créons des interfaces en utilisant des classes de base abstraites où 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 doivent être abstraites - elles définissent ce que les classes d'implémentation 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 indices 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, pas comment elles le font. Utilisez des classes de base abstraites avec uniquement des méthodes abstraites pour créer des contrats clairs que les classes d'implémentation doivent suivre. Cela garantit un comportement cohérent à travers 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émentez les classes de base abstraites (interfaces)song.py- Implémentez la classe Songvideo.py- Implémentez la classe Videomediaplayer.py- Implémentez la classe MediaPlayer
Chaque fichier contient des commentaires TODO détaillés pour guider votre implémentation. Suivez ces commentaires pour créer un système de lecteur multimédia complet avec un héritage et une implémentation d'interface appropriés.
Aide-mémoire
Créez des interfaces en utilisant des classes de base abstraites avec le module abc :
from abc import ABC, abstractmethodDéfinissez une interface avec uniquement des méthodes abstraites :
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passImplémentez l'interface dans des classes concrètes :
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}"Utilisez les interfaces de manière polymorphe :
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
print(shape.draw())
print(shape.resize(10, 8))Utilisez les interfaces comme indices de type (type hints) :
def render_shape(drawable: Drawable):
return drawable.draw()Les interfaces définissent ce que les classes doivent faire, et non comment elles le font. Toutes les méthodes d'une interface doivent être abstraites pour créer des contrats clairs pour les classes d'implémentation.
Essayez vous-même
from song import Song
from video import Video
from mediaplayer import MediaPlayer
from playable import Playable, MediaInfo
# Gestionnaire de cas de test complet
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":
# Test du lecteur multimédia sans aucun média défini
player = MediaPlayer()
print(player.play()) # Devrait afficher "No media set"
print(player.pause()) # Devrait afficher "No media set"
print(player.stop()) # Devrait afficher "No media set"
elif test_case == "time_formatting":
# Test du 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":
# Test que Song et Video implémentent correctement les interfaces
song = Song("Test Song", "Test Artist", 180)
video = Video("Test Video", "480p", 240)
# Vérification de l'implémentation des interfaces
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 de toutes les méthodes d'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":
# Test du 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":
# Test des 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émentation d'un test de charge avec de nombreux objets multimédias
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()
# Test avec toutes les chansons
for i, song in enumerate(songs):
player.set_media(song)
if i % 10 == 0: # Affiche seulement un élément sur 10 pour éviter trop de sorties
print(f"Playing song {i+1}: {player.play()}")
# Test avec toutes les vidéos
for i, video in enumerate(videos):
player.set_media(video)
if i % 10 == 0: # Affiche seulement un élément sur 10 pour éviter trop de sorties
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 Object Oriented Programming
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 bancaire