Menu
Coddy logo textTech

Design de Interfaces

Parte da seção Programação Orientada a Objetos do Journey de Python da Coddy. Lição 26 de 64.

Uma interface define um contrato que as classes devem seguir. Em Python, criamos interfaces usando classes base abstratas nas quais todos os métodos são abstratos.

Importe o módulo abc:

from abc import ABC, abstractmethod

Crie uma interface apenas com métodos abstratos:

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

Todos os métodos em uma interface devem ser abstratos — eles definem o que as classes que os implementam devem fazer, não como fazê-lo.

Implemente a interface em uma classe 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}"

Crie outra classe que implemente a mesma 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}"

Use a interface polimorficamente:

shapes = [Circle(5), Rectangle(3, 4)]

for shape in shapes:
    print(shape.draw())
    print(shape.resize(10, 8))

Saída:

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

Você também pode usar interfaces como dicas de tipo:

def render_shape(drawable: Drawable):
    return drawable.draw()

circle = Circle(3)
print(render_shape(circle))

Saída:

Drawing a circle

Ponto Chave: Interfaces definem o que as classes devem fazer, não como elas fazem. Use classes base abstratas com apenas métodos abstratos para criar contratos claros que as classes implementadoras devem seguir. Isso garante um comportamento consistente entre diferentes implementações.

challenge icon

Desafio

Médio

Neste desafio, você implementará um sistema de reprodutor de mídia com interfaces.

Você precisa editar os seguintes arquivos:

  • playable.py - Implemente as classes base abstratas (interfaces)
  • song.py - Implemente a classe Song
  • video.py - Implemente a classe Video
  • mediaplayer.py - Implemente a classe MediaPlayer

Cada arquivo contém comentários TODO detalhados para orientar sua implementação. Siga esses comentários para criar um sistema completo de reprodutor de mídia com herança adequada e implementação de interfaces.

Experimente você mesmo

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

# Manipulador abrangente de casos de teste
test_case = input()

if test_case == "default_test":
    # Caso de teste padrão do problema original
    song = Song("Bohemian Rhapsody", "Queen", 355)
    video = Video("Python Tutorial", "1080p", 1800)
    player = MediaPlayer()

    # Teste com música
    player.set_media(song)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())
    print()  # Linha vazia para legibilidade

    # Teste com vídeo
    player.set_media(video)
    print(player.current_media.get_info())
    print(player.play())
    print(player.pause())
    print(player.stop())

elif test_case == "empty_player":
    # Testa o reprodutor de mídia sem nenhuma mídia definida
    player = MediaPlayer()
    print(player.play())  # Deve imprimir "No media set"
    print(player.pause())  # Deve imprimir "No media set"
    print(player.stop())  # Deve imprimir "No media set"

elif test_case == "time_formatting":
    # Testa a formatação de tempo no 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":
    # Testa se Song e Video implementam as interfaces corretamente
    song = Song("Test Song", "Test Artist", 180)
    video = Video("Test Video", "480p", 240)
    
    # Verifica a implementação da 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)}")
    
    # Testa todos os métodos da 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":
    # Testa o comportamento polimórfico com uma lista de diferentes tipos de mídia
    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":
    # Testa casos extremos
    empty_song = Song("", "", 0)
    edge_video = Video("A" * 100, "", -10)  # Título muito longo, resolução vazia, duração 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 um teste de estresse com muitos objetos de 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()
    
    # Teste com todas as músicas
    for i, song in enumerate(songs):
        player.set_media(song)
        if i % 10 == 0:  # Imprime apenas a cada 10 itens para evitar excesso de saída
            print(f"Playing song {i+1}: {player.play()}")
    
    # Teste com todos os vídeos
    for i, video in enumerate(videos):
        player.set_media(video)
        if i % 10 == 0:  # Imprime apenas a cada 10 itens para evitar excesso de saída
            print(f"Playing video {i+1}: {player.play()}")
    
    print("Stress test completed successfully!")
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Python online