Menu
Coddy logo textTech

Adaptermuster

Teil des Abschnitts Objektorientierte Programmierung der Python-Journey von Coddy. Lektion 50 von 64.

Das Adapter-Muster ermöglicht es Objekten mit inkompatiblen Schnittstellen, zusammenzuarbeiten. Es fungiert als Brücke, indem es eine vorhandene Klasse mit einer neuen Schnittstelle umhüllt, die Clients erwarten.

Hier sind zwei Systeme mit inkompatiblen Schnittstellen:

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

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

Der alte Drucker verwendet old_print(), während der neue print() verwendet.

Erstelle einen Adapter, damit der alte Drucker mit der neuen Schnittstelle funktioniert:

class PrinterAdapter:
    def __init__(self, old_printer):
        self.old_printer = old_printer
    
    def print(self, text):
        # Alte Schnittstelle an neue Schnittstelle anpassen
        return self.old_printer.old_print(text)

Der Adapter kapselt den alten Drucker und stellt die erwartete Schnittstelle bereit.

Verwende beide Drucker mit demselben Client-Code:

def print_document(printer, text):
    return printer.print(text)  # Erwartet print()-Methode

# Neuen Drucker direkt verwenden
new_printer = NewPrinter()
print(print_document(new_printer, "Hello"))

# Alten Drucker über Adapter verwenden
old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)
print(print_document(adapter, "Hello"))

Erstelle ein weiteres Beispiel mit Mediaplayern:

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"))

Ausgabe:

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

Wichtiger Punkt: Das Adapter-Muster ermöglicht das Zusammenspiel inkompatibler Schnittstellen, indem eine vorhandene Klasse mit einer neuen Schnittstelle umschlossen wird. Der Adapter übersetzt Aufrufe von der erwarteten Schnittstelle in die tatsächliche Schnittstelle des umschlossenen Objekts. Dies ist nützlich, um Legacy-Code oder Bibliotheken von Drittanbietern zu integrieren, ohne bestehenden Code zu ändern.

challenge icon

Aufgabe

Mittel

In dieser Herausforderung implementierst du das Adapter-Entwurfsmuster, um Legacy-Systeme in eine moderne Anwendungsarchitektur zu integrieren. Das Adapter-Muster ermöglicht es Objekten mit inkompatiblen Schnittstellen, zusammenzuarbeiten, indem ein Wrapper (Adapter) erstellt wird, der eine Schnittstelle in eine andere übersetzt.

 

Dein Unternehmen verfügt über ein Legacy-System zur Datenanalyse und -visualisierung, das in eine neue moderne Analyseplattform integriert werden muss. Die Legacy-Komponenten verfügen über Schnittstellen, die mit dem neuen System inkompatibel sind. Anstatt den Legacy-Code neu zu schreiben (was riskant und teuer wäre), wurdest du damit beauftragt, Adapter zu erstellen, damit diese Komponenten mit dem neuen System funktionieren.

Du musst:

  1. Die modernen Schnittstellen verstehen, die in interfaces.py definiert sind (diese Datei darf nicht geändert werden)
  2. Die Legacy-Komponenten in legacy_system.py untersuchen (diese Datei darf nicht geändert werden)
  3. Adapterklassen in adapters.py implementieren, die die Legacy-Komponenten mit den modernen Schnittstellen kompatibel machen
  4. Ein modernes System in modern_system.py erstellen, das diese Schnittstellen verwendet

Probier es selbst

# Importiere alle notwendigen Klassen
from adapters import LegacyDataAnalyzerAdapter, LegacyChartGeneratorAdapter
from modern_system import AnalyticsSystem

# Umfassender Testfall-Handler
test_case = input()

if test_case == "basic_adapter_test":
    # Teste grundlegende Adapter-Funktionalität
    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":
    # Teste Visualizer-Adapter
    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":
    # Teste vollständiges Analytics-System
    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":
    # Teste mit leeren Daten
    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":
    # Teste verschiedene Diagrammtypen
    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":
    # Teste Behandlung von Dateierweiterungen
    visualizer = LegacyChartGeneratorAdapter()
    data = [1, 2, 3, 4]
    visualizer.visualize(data)
    
    # Teste verschiedene Dateinamenformate
    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":
    # Teste mit gemischten numerischen Daten
    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":
    # Teste mit ungültigen numerischen Daten
    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":
    # Teste Zusammenfassung ohne Ergebnisse
    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":
    # Test mit größerem Datensatz
    processor = LegacyDataAnalyzerAdapter()
    data = list(range(1, 101))  # 1 bis 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]
    
    # Analytics-Systeme mit verschiedenen Visualisierern erstellen
    bar_system = AnalyticsSystem(processor, bar_visualizer)
    line_system = AnalyticsSystem(LegacyDataAnalyzerAdapter(), line_visualizer)
    
    # Analysen durchführen
    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']}")
    
    # Zusammenfassungen abrufen
    print("Bar system summary:")
    print(bar_system.get_analysis_summary())
    print("Line system summary:")
    print(line_system.get_analysis_summary())
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Python-Compiler