Menu
CoddyTech

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 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 10x8

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

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

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 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!")
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