Menu
CoddyTech

Diseño de interfaces

Parte de la sección Programación orientada a objetos del Journey de Python de Coddy. Lección 26 de 64.

Una interfaz define un contrato que las clases deben cumplir. En Python, creamos interfaces mediante clases base abstractas en las que todos los métodos son abstractos.

Importa el módulo abc:

from abc import ABC, abstractmethod

Crea una interfaz solo con métodos abstractos:

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

Todos los métodos de una interfaz deben ser abstractos: definen lo que deben hacer las clases que la implementan, no cómo hacerlo.

Implementa la interfaz en una clase 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 otra clase que implemente la misma interfaz:

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 la interfaz de forma polimórfica:

shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
    print(shape.draw())
    print(shape.resize(10, 8))

Salida:

Drawing a circle
Resized circle to radius 4.0
Drawing a rectangle
Resized rectangle to 10x8

También puedes usar interfaces como anotaciones de tipo:

def render_shape(drawable: Drawable):
    return drawable.draw()
circle = Circle(3)
print(render_shape(circle))

Salida:

Drawing a circle

Punto clave: Las interfaces definen qué deben hacer las clases, no cómo lo hacen. Usa clases base abstractas con solo métodos abstractos para crear contratos claros que las clases implementadoras deben seguir. Esto garantiza un comportamiento coherente entre distintas implementaciones.

challenge icon

Desafío

Intermedio

En este desafío, implementarás un sistema de reproductor multimedia con interfaces.

Tienes que editar los siguientes archivos:

  • playable.py - Implementa las clases base abstractas (interfaces)
  • song.py - Implementa la clase Song
  • video.py - Implementa la clase Video
  • mediaplayer.py - Implementa la clase MediaPlayer

Cada archivo contiene comentarios detallados de TODO para guiar tu implementación. Sigue estos comentarios para crear un sistema de reproductor multimedia completo con la herencia y la implementación de interfaces adecuadas.

Pruébalo tú mismo

from song import Song
from video import Video
from mediaplayer import MediaPlayer
from playable import Playable, MediaInfo

# Gestor completo de casos de prueba
test_case = input()

if test_case == "default_test":
    # Caso de prueba predeterminado del problema original
    song = Song("Bohemian Rhapsody", "Queen", 355)
    video = Video("Python Tutorial", "1080p", 1800)
    player = MediaPlayer()

    # Prueba con una canción
    player.set_media(song)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())
    print()  # Línea en blanco para facilitar la lectura

    # Prueba 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":
    # Prueba el reproductor multimedia sin ningún medio configurado
    player = MediaPlayer()
    print(player.play())  # Debería imprimir "No media set"
    print(player.pause())  # Debería imprimir "No media set"
    print(player.stop())  # Debería imprimir "No media set"

elif test_case == "time_formatting":
    # Prueba el formato de tiempo en el método 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":
    # Comprueba que Song y Video implementen correctamente las interfaces
    song = Song("Test Song", "Test Artist", 180)
    video = Video("Test Video", "480p", 240)
    
    # Comprueba la implementación de las 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)}")
    
    # Prueba todos los métodos de las interfaces
    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":
    # Prueba el comportamiento polimórfico con una lista de distintos tipos de medios
    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":
    # Prueba los casos límite
    empty_song = Song("", "", 0)
    edge_video = Video("A" * 100, "", -10)  # Título muy largo, resolución vacía, duración 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 una prueba de estrés con muchos objetos multimedia
    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()
    
    # Prueba con todas las canciones
    for i, song in enumerate(songs):
        player.set_media(song)
        if i % 10 == 0:  # Imprime solo uno de cada 10 para evitar demasiada salida
            print(f"Playing song {i+1}: {player.play()}")
    
    # Prueba con todos los vídeos
    for i, video in enumerate(videos):
        player.set_media(video)
        if i % 10 == 0:  # Imprime solo uno de cada 10 para evitar demasiada salida
            print(f"Playing video {i+1}: {player.play()}")
    
    print("Stress test completed successfully!")
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de Python online