Menu
Coddy logo textTech

Padrão Adapter

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

O Padrão Adapter permite que objetos com interfaces incompatíveis trabalhem juntos. Ele atua como uma ponte, envolvendo uma classe existente com uma nova interface que os clientes esperam.

Aqui estão dois sistemas com interfaces incompatíveis:

class OldPrinter:
    def old_print(self, text):
        return f"OLD: {text}"

class NewPrinter:
    def print(self, text):
        return f"NEW: {text}"

A impressora antiga usa old_print(), enquanto a nova usa print().

Crie um adaptador para fazer a impressora antiga funcionar com a nova interface:

class PrinterAdapter:
    def __init__(self, old_printer):
        self.old_printer = old_printer
    
    def print(self, text):
        # Adaptar a interface antiga para a nova interface
        return self.old_printer.old_print(text)

O adaptador envolve a impressora antiga e fornece a interface esperada.

Use ambas as impressoras com o mesmo código do cliente:

def print_document(printer, text):
    return printer.print(text)  # Espera o método print()

# Use a nova impressora diretamente
new_printer = NewPrinter()
print(print_document(new_printer, "Hello"))

# Use a impressora antiga através do adaptador
old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)
print(print_document(adapter, "Hello"))

Crie outro exemplo com reprodutores de mídia:

class Mp3Player:
    def play_mp3(self, filename):
        return f"Playing MP3: {filename}"

class Mp4Player:
    def play_mp4(self, filename):
        return f"Playing MP4: {filename}"

class MediaAdapter:
    def __init__(self, player, audio_type):
        self.player = player
        self.audio_type = audio_type
    
    def play(self, filename):
        if self.audio_type == "mp3":
            return self.player.play_mp3(filename)
        elif self.audio_type == "mp4":
            return self.player.play_mp4(filename)
class AudioPlayer:
    def play(self, audio_type, filename):
        if audio_type == "mp3":
            return Mp3Player().play_mp3(filename)
        else:
            adapter = MediaAdapter(Mp4Player(), audio_type)
            return adapter.play(filename)

player = AudioPlayer()
print(player.play("mp3", "song.mp3"))
print(player.play("mp4", "video.mp4"))

Saída:

NEW: Hello
OLD: Hello
Playing MP3: song.mp3
Playing MP4: video.mp4

Ponto-chave: o Padrão Adapter faz com que interfaces incompatíveis trabalhem juntas ao envolver uma classe existente com uma nova interface. O adaptador traduz chamadas da interface esperada para a interface real do objeto envolvido. Isso é útil para integrar código legado ou bibliotecas de terceiros sem modificar o código existente.

challenge icon

Desafio

Médio

Neste desafio, você implementará o padrão de projeto Adapter para integrar sistemas legados a uma arquitetura de aplicativo moderna. O padrão Adapter permite que objetos com interfaces incompatíveis trabalhem juntos, criando um wrapper (adaptador) que traduz uma interface para outra.

 

Sua empresa possui um sistema legado de análise e visualização de dados que precisa ser integrado a uma nova plataforma moderna de análise. Os componentes legados têm interfaces incompatíveis com o novo sistema. Em vez de reescrever o código legado (o que seria arriscado e caro), você foi encarregado de criar adaptadores para fazer esses componentes funcionarem com o novo sistema.

Você precisa:

  1. Entender as interfaces modernas definidas em interfaces.py (este arquivo não pode ser modificado)
  2. Examinar os componentes legados em legacy_system.py (este arquivo não pode ser modificado)
  3. Implementar classes adaptadoras em adapters.py que tornem os componentes legados compatíveis com as interfaces modernas
  4. Criar um sistema moderno em modern_system.py que use essas interfaces

Experimente você mesmo

# Importar todas as classes necessárias
from adapters import LegacyDataAnalyzerAdapter, LegacyChartGeneratorAdapter
from modern_system import AnalyticsSystem

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

if test_case == "basic_adapter_test":
    # Testar funcionalidade básica do adaptador
    processor = LegacyDataAnalyzerAdapter()
    data = [1, 2, 3, 4, 5]
    processor.process_data(data)
    results = processor.get_results()
    print(f"Results: {results}")

elif test_case == "visualizer_adapter_test":
    # Testar adaptador do visualizador
    visualizer = LegacyChartGeneratorAdapter("bar")
    data = [10, 20, 30, 40, 50]
    success = visualizer.visualize(data)
    if success:
        export_success = visualizer.export_visualization("test_chart.png")
        print(f"Visualization exported: {export_success}")

elif test_case == "analytics_system_test":
    # Testar sistema completo de análise
    processor = LegacyDataAnalyzerAdapter()
    visualizer = LegacyChartGeneratorAdapter("line")
    system = AnalyticsSystem(processor, visualizer)
    
    data = [15, 25, 35, 45, 55]
    result = system.analyze_and_visualize(data, "analytics_output.png")
    print(f"System result: {result}")

elif test_case == "validation_error_test":
    # Test validation errors
    processor = LegacyDataAnalyzerAdapter()
    try:
        processor.process_data("invalid_data")
        print("Validation failed - should have raised ValueError")
    except ValueError as e:
        print(f"Validation error caught: {e}")

elif test_case == "empty_data_test":
    # Testar com dados vazios
    processor = LegacyDataAnalyzerAdapter()
    try:
        processor.process_data([])
        results = processor.get_results()
        print(f"Empty data results: {results}")
    except Exception as e:
        print(f"Empty data error: {e}")

elif test_case == "chart_types_test":
    # Testar diferentes tipos de gráfico
    chart_types = ["bar", "line", "pie"]
    data = [5, 15, 25, 35]
    
    for chart_type in chart_types:
        visualizer = LegacyChartGeneratorAdapter(chart_type)
        success = visualizer.visualize(data)
        print(f"{chart_type} chart created: {success}")

elif test_case == "file_extension_test":
    # Testar tratamento de extensão de arquivo
    visualizer = LegacyChartGeneratorAdapter()
    data = [1, 2, 3, 4]
    visualizer.visualize(data)
    
    # Testar vários formatos de nome de arquivo
    filenames = ["test", "test.jpg", "test.pdf", "test.png"]
    for filename in filenames:
        success = visualizer.export_visualization(filename)
        print(f"Export '{filename}': {success}")

elif test_case == "summary_test":
    # Test analysis summary
    processor = LegacyDataAnalyzerAdapter()
    visualizer = LegacyChartGeneratorAdapter()
    system = AnalyticsSystem(processor, visualizer)
    
    data = [10, 20, 30, 40, 50, 60]
    system.analyze_and_visualize(data)
    summary = system.get_analysis_summary()
    print("Analysis Summary:")
    print(summary)

elif test_case == "mixed_data_test":
    # Testar com dados numéricos mistos
    processor = LegacyDataAnalyzerAdapter()
    data = [1.5, 2, 3.7, 4, 5.2]
    processor.process_data(data)
    results = processor.get_results()
    print(f"Mixed data results: {results}")

elif test_case == "invalid_numeric_test":
    # Testar com dados numéricos inválidos
    processor = LegacyDataAnalyzerAdapter()
    try:
        processor.process_data([1, 2, "three", 4, 5])
        print("Validation failed - should have raised ValueError")
    except ValueError as e:
        print(f"Invalid numeric data error: {e}")

elif test_case == "no_results_summary_test":
    # Testar resumo sem resultados
    processor = LegacyDataAnalyzerAdapter()
    visualizer = LegacyChartGeneratorAdapter()
    system = AnalyticsSystem(processor, visualizer)
    
    summary = system.get_analysis_summary()
    print(f"No results summary: {summary}")

elif test_case == "large_dataset_test":
    # Teste com conjunto de dados maior
    processor = LegacyDataAnalyzerAdapter()
    data = list(range(1, 101))  # 1 a 100
    processor.process_data(data)
    results = processor.get_results()
    print(f"Large dataset - Mean: {results.get('mean', 'N/A'):.2f}")
    print(f"Large dataset - Min: {results.get('min', 'N/A')}")
    print(f"Large dataset - Max: {results.get('max', 'N/A')}")

elif test_case == "complete_workflow_test":
    # Test complete workflow with multiple operations
    processor = LegacyDataAnalyzerAdapter()
    bar_visualizer = LegacyChartGeneratorAdapter("bar")
    line_visualizer = LegacyChartGeneratorAdapter("line")
    
    data = [12, 18, 25, 32, 28, 35, 42]
    
    # Cria sistemas de analytics com visualizadores diferentes
    bar_system = AnalyticsSystem(processor, bar_visualizer)
    line_system = AnalyticsSystem(LegacyDataAnalyzerAdapter(), line_visualizer)
    
    # Executa as análises
    bar_result = bar_system.analyze_and_visualize(data, "bar_chart.png")
    line_result = line_system.analyze_and_visualize(data, "line_chart.png")
    
    print("Complete workflow test completed")
    print(f"Bar chart result: {bar_result['visualization_file']}")
    print(f"Line chart result: {line_result['visualization_file']}")
    
    # Obtém os resumos
    print("Bar system summary:")
    print(bar_system.get_analysis_summary())
    print("Line system summary:")
    print(line_system.get_analysis_summary())
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