Menu
Coddy logo textTech

Wzorzec Adapter

Część sekcji Programowanie obiektowe ścieżki Python w Coddy. Lekcja 50 z 64.

Wzorzec Adapter umożliwia współpracę obiektom o niezgodnych interfejsach. Działa jak most, opakowując istniejącą klasę w nowy interfejs, którego oczekują klienci.

Oto dwa systemy z niekompatybilnymi interfejsami:

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

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

Stara drukarka używa old_print(), a nowa print().

Utwórz adapter, aby stara drukarka działała z nowym interfejsem:

class PrinterAdapter:
    def __init__(self, old_printer):
        self.old_printer = old_printer
    
    def print(self, text):
        # Dostosuj stary interfejs do nowego interfejsu
        return self.old_printer.old_print(text)

Adapter opakowuje starą drukarkę i udostępnia oczekiwany interfejs.

Użyj obu drukarek z tym samym kodem klienta:

def print_document(printer, text):
    return printer.print(text)  # Oczekuje metody print()

# Użyj nowej drukarki bezpośrednio
new_printer = NewPrinter()
print(print_document(new_printer, "Hello"))

# Użyj starej drukarki przez adapter
old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)
print(print_document(adapter, "Hello"))

Utwórz kolejny przykład z odtwarzaczami multimedialnymi:

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

Wynik:

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

Kluczowa kwestia: Wzorzec Adaptera umożliwia współpracę niekompatybilnych interfejsów, opakowując istniejącą klasę w nowy interfejs. Adapter tłumaczy wywołania z oczekiwanego interfejsu na rzeczywisty interfejs opakowanego obiektu. Jest to przydatne przy integrowaniu starszego kodu lub bibliotek innych firm bez modyfikowania istniejącego kodu.

challenge icon

Wyzwanie

Średni

W tym wyzwaniu zaimplementujesz wzorzec projektowy Adapter, aby zintegrować starsze systemy z nowoczesną architekturą aplikacji. Wzorzec Adapter pozwala współpracować obiektom z niezgodnymi interfejsami, tworząc opakowanie (adapter), które tłumaczy jeden interfejs na inny.

 

Twoja firma ma starszy system analizy i wizualizacji danych, który trzeba zintegrować z nową, nowoczesną platformą analityczną. Starsze komponenty mają interfejsy niezgodne z nowym systemem. Zamiast przepisywać starszy kod (co byłoby ryzykowne i kosztowne), masz za zadanie utworzyć adaptery, które umożliwią współpracę tych komponentów z nowym systemem.

Musisz:

  1. Zapoznać się z nowoczesnymi interfejsami zdefiniowanymi w interfaces.py (tego pliku nie można modyfikować)
  2. Przeanalizować starsze komponenty w legacy_system.py (tego pliku nie można modyfikować)
  3. Zaimplementować klasy adapterów w adapters.py, które dostosują starsze komponenty do nowoczesnych interfejsów
  4. Utworzyć nowoczesny system w modern_system.py, który korzysta z tych interfejsów

Spróbuj swoich sił

# Importuj wszystkie niezbędne klasy
from adapters import LegacyDataAnalyzerAdapter, LegacyChartGeneratorAdapter
from modern_system import AnalyticsSystem

# Kompleksowa obsługa przypadków testowych
test_case = input()

if test_case == "basic_adapter_test":
    # Przetestuj podstawowe działanie adaptera
    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":
    # Przetestuj adapter wizualizacji
    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":
    # Przetestuj cały system analityczny
    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":
    # Przetestuj błędy walidacji
    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":
    # Przetestuj działanie z pustymi danymi
    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":
    # Przetestuj różne typy wykresów
    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":
    # Przetestuj obsługę rozszerzeń plików
    visualizer = LegacyChartGeneratorAdapter()
    data = [1, 2, 3, 4]
    visualizer.visualize(data)
    
    # Przetestuj różne formaty nazw plików
    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":
    # Przetestuj podsumowanie analizy
    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":
    # Przetestuj działanie z danymi zawierającymi różne typy liczb
    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":
    # Przetestuj nieprawidłowe dane liczbowe
    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":
    # Przetestuj podsumowanie bez wyników
    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":
    # Przetestuj na większym zbiorze danych
    processor = LegacyDataAnalyzerAdapter()
    data = list(range(1, 101))  # Od 1 do 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":
    # Przetestuj pełny przebieg pracy z wieloma operacjami
    processor = LegacyDataAnalyzerAdapter()
    bar_visualizer = LegacyChartGeneratorAdapter("bar")
    line_visualizer = LegacyChartGeneratorAdapter("line")
    
    data = [12, 18, 25, 32, 28, 35, 42]
    
    # Utwórz systemy analityczne z różnymi wizualizatorami
    bar_system = AnalyticsSystem(processor, bar_visualizer)
    line_system = AnalyticsSystem(LegacyDataAnalyzerAdapter(), line_visualizer)
    
    # Uruchom analizy
    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']}")
    
    # Pobierz podsumowania
    print("Bar system summary:")
    print(bar_system.get_analysis_summary())
    print("Line system summary:")
    print(line_system.get_analysis_summary())
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Python online