Design de Interfaces
Parte da seção Object Oriented Programming 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 onde todos os métodos são abstratos.
Importe o módulo abc:
from abc import ABC, abstractmethodCrie uma interface apenas com métodos abstratos:
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passTodos os métodos em uma interface devem ser abstratos - eles definem o que as classes implementadoras 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 de forma polimórfica:
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 10x8Você também pode usar interfaces como dicas de tipo (type hints):
def render_shape(drawable: Drawable):
return drawable.draw()
circle = Circle(3)
print(render_shape(circle))Saída:
Drawing a circlePonto 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.
Desafio
MédioNeste desafio, você implementará um sistema de player de mídia com interfaces.
Você precisa editar os seguintes arquivos:
playable.py- Implementar as classes base abstratas (interfaces)song.py- Implementar a classe Songvideo.py- Implementar a classe Videomediaplayer.py- Implementar a classe MediaPlayer
Cada arquivo contém comentários TODO detalhados para guiar sua implementação. Siga estes comentários para criar um sistema de player de mídia completo com herança e implementação de interface adequadas.
Folha de consulta
Crie interfaces usando classes base abstratas com o módulo abc:
from abc import ABC, abstractmethodDefina uma interface apenas com métodos abstratos:
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
@abstractmethod
def resize(self, width, height):
passImplemente a interface em classes concretas:
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}"Use interfaces de forma polimórfica:
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
print(shape.draw())
print(shape.resize(10, 8))Use interfaces como dicas de tipo (type hints):
def render_shape(drawable: Drawable):
return drawable.draw()Interfaces definem o que as classes devem fazer, não como elas fazem. Todos os métodos em uma interface devem ser abstratos para criar contratos claros para as classes implementadoras.
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!")Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosO Parâmetro selfMétodosAtributosMétodo Construtor (__init__)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Função super()Sobrescrita de MétodoHerança MúltiplaOrdem de Resolução de MétodosRecapitulação - Hierarquia de Funcionários7Métodos Especiais
Introdução aos Métodos MágicosSobrecarga de OperadoresMétodos Mágicos de ContêinerRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução a Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy2Decoradores
Introdução aos DecoradoresDecorador de PropriedadeDecorador de Método EstáticoDecorador de Método de Classe5Polimorfismo
Sobrescrita de Método RevisitadaDuck TypingClasses e Métodos AbstratosDesign de InterfacesRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição vs HerançaMixinsMétodos Estáticos e de ClasseDecoradores de ClasseGerenciadores de Contexto11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Propriedades de Classe
Variáveis de Instância vs de ClasseDecoradores de PropriedadeAtributos PrivadosRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Membros Públicos, Protegidos e PrivadosModificadores de AcessoOcultação de InformaçãoProperty Decorators AvançadosRecapitulação - Sistema de Registro de Alunos12Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário