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.mp4Wichtiger 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.
Aufgabe
MittelIn 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:
- Die modernen Schnittstellen verstehen, die in
interfaces.pydefiniert sind (diese Datei darf nicht geändert werden) - Die Legacy-Komponenten in
legacy_system.pyuntersuchen (diese Datei darf nicht geändert werden) - Adapterklassen in
adapters.pyimplementieren, die die Legacy-Komponenten mit den modernen Schnittstellen kompatibel machen - Ein modernes System in
modern_system.pyerstellen, 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())Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktormethode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlegende VererbungDie super()-FunktionMethodenüberschreibungMehrfachvererbungMethodenauflösungsreihenfolgeWiederholung – Mitarbeiterhierarchie7Spezielle Methoden
Einführung in magische MethodenOperatorüberladungMagische Methoden für ContainerRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformBankensystemEntwicklung von SpielfigurenFahrzeugvermietungsservice2Dekoratoren
Einführung in DekoratorenProperty-DekoratorDekorator für statische MethodenDekorator für Klassenmethoden5Polymorphie
Methodenüberschreibung erneut betrachtetDuck-TypingAbstrakte Klassen und MethodenSchnittstellendesignRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische Methoden und KlassenmethodenKlassen-DekoratorenKontextmanager11Entwurfsmuster Teil 2
BefehlsmusterAdaptermusterDekorierermusterSchablonenmethodenmusterZustandsmusterKompositumsmuster3Klassenattribute
Instanz- vs. KlassenvariablenProperty-DecoratorsPrivate AttributeWiederholung – Bankkontoverwaltung6Kapselung
Öffentliche, geschützte, private MemberZugriffsmodifikatorenInformationsverbergungProperty-Decorators – FortgeschrittenWiederholung – System zur Verwaltung von Studentendaten12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und BenutzerklassenAusleihsystemSuchfunktionAdministrationsoberflächeTests und IntegrationÜbe selbstständig: Online-Python-Compiler