Menu
Coddy logo textTech

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, abstractmethod

Créez une interface avec uniquement des méthodes abstraites :

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

Toutes les méthodes d’une interface doivent ê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 10x8

Vous 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 circle

Point 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.

challenge icon

Défi

Moyen

Dans 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 Song
  • video.py - Implémenter la classe Video
  • mediaplayer.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 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!")
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur Python en ligne