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 seguir. 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 con solo 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 los 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 polimórficamente:

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 sugerencias 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 lo que las clases deben hacer, no cómo lo hacen. Usa clases base abstractas con solo métodos abstractos para crear contratos claros que las clases que los implementan 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.

Debes 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 TODO detallados para guiar tu implementación. Sigue estos comentarios para crear un sistema completo de reproductor multimedia con una herencia adecuada y la implementación de interfaces.

Pruébalo tú mismo

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

# Manejador integral 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 canción
    player.set_media(song)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())
    print()  # Línea vacía para legibilidad

    # Prueba con 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 de medios sin medios establecidos
    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":
    # 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":
    # Prueba que Song y Video implementen correctamente las interfaces
    song = Song("Test Song", "Test Artist", 180)
    video = Video("Test Video", "480p", 240)
    
    # Comprobar la implementación de la interfaz
    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)}")
    
    # Probar todos los métodos de la interfaz
    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":
    # Probar el comportamiento polimórfico con una lista de diferentes 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":
    # Probar 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 cada décimo para evitar demasiada salida
            print(f"Playing song {i+1}: {player.play()}")
    
    # Prueba con todos los videos
    for i, video in enumerate(videos):
        player.set_media(video)
        if i % 10 == 0:  # Imprime solo cada décimo 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