Menu
CoddyTech

Mẫu bộ chuyển đổi

Thuộc phần Lập trình hướng đối tượng trong hành trình Python của Coddy. Bài học 50 trên 64.

Mẫu Adapter cho phép các đối tượng có giao diện không tương thích hoạt động cùng nhau. Mẫu này đóng vai trò như một cầu nối bằng cách bọc một lớp hiện có trong giao diện mới mà phía sử dụng mong đợi.

Đây là hai hệ thống có giao diện không tương thích:

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

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

Máy in cũ dùng old_print(), còn máy in mới dùng print().

Tạo một bộ chuyển đổi để máy in cũ hoạt động với giao diện mới:

class PrinterAdapter:
    def __init__(self, old_printer):
        self.old_printer = old_printer
    
    def print(self, text):
        # Điều chỉnh giao diện cũ cho phù hợp với giao diện mới
        return self.old_printer.old_print(text)

Bộ chuyển đổi bao bọc máy in cũ và cung cấp giao diện mong đợi.

Dùng cả hai máy in với cùng một đoạn code phía client:

def print_document(printer, text):
    return printer.print(text)  # Yêu cầu phương thức (method) print()

# Dùng máy in mới trực tiếp
new_printer = NewPrinter()
print(print_document(new_printer, "Hello"))

# Dùng máy in cũ thông qua bộ chuyển đổi
old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)
print(print_document(adapter, "Hello"))

Tạo thêm một ví dụ với trình phát đa phương tiện:

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

Đầu ra:

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

Điểm chính: Mẫu Adapter giúp các giao diện không tương thích hoạt động cùng nhau bằng cách bọc một lớp hiện có bằng giao diện mới. Bộ chuyển đổi chuyển đổi các lệnh gọi từ giao diện được mong đợi sang giao diện thực tế của đối tượng được bọc. Cách này hữu ích khi tích hợp code cũ hoặc thư viện bên thứ ba mà không cần sửa đổi code hiện có.

challenge icon

Thử thách

Trung bình

Trong thử thách này, bạn sẽ triển khai mẫu thiết kế Adapter để tích hợp các hệ thống cũ với kiến trúc ứng dụng hiện đại. Mẫu Adapter cho phép các đối tượng có giao diện không tương thích hoạt động cùng nhau bằng cách tạo một lớp bọc (adapter) để chuyển đổi giao diện này sang giao diện khác.

 

Công ty bạn có một hệ thống phân tích và trực quan hóa dữ liệu cũ cần tích hợp với một nền tảng phân tích hiện đại mới. Các thành phần cũ có giao diện không tương thích với hệ thống mới. Thay vì viết lại code cũ (việc này tiềm ẩn rủi ro và tốn kém), bạn được giao nhiệm vụ tạo các adapter để giúp những thành phần này hoạt động với hệ thống mới.

Bạn cần:

  1. Tìm hiểu các giao diện hiện đại được định nghĩa trong interfaces.py (không thể chỉnh sửa tệp này)
  2. Xem xét các thành phần cũ trong legacy_system.py (không thể chỉnh sửa tệp này)
  3. Triển khai các lớp adapter trong adapters.py để giúp các thành phần cũ tương thích với các giao diện hiện đại
  4. Tạo một hệ thống hiện đại trong modern_system.py sử dụng các giao diện này

Tự làm thử

# Nhập tất cả các lớp cần thiết
from adapters import LegacyDataAnalyzerAdapter, LegacyChartGeneratorAdapter
from modern_system import AnalyticsSystem

# Xử lý toàn diện các test case
test_case = input()

if test_case == "basic_adapter_test":
    # Kiểm tra chức năng cơ bản của adapter
    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":
    # Kiểm tra adapter của trình trực quan hóa
    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":
    # Kiểm tra toàn bộ hệ thống phân tích dữ liệu
    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":
    # Kiểm tra lỗi xác thực
    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":
    # Kiểm tra với dữ liệu trống
    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":
    # Kiểm tra các loại biểu đồ khác nhau
    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":
    # Kiểm tra cách xử lý phần mở rộng của tệp
    visualizer = LegacyChartGeneratorAdapter()
    data = [1, 2, 3, 4]
    visualizer.visualize(data)
    
    # Kiểm tra các định dạng tên tệp khác nhau
    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":
    # Kiểm tra phần tóm tắt kết quả phân tích
    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":
    # Kiểm tra với dữ liệu gồm cả số nguyên và số thực
    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":
    # Kiểm tra với dữ liệu số không hợp lệ
    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":
    # Kiểm tra phần tóm tắt khi không có kết quả
    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":
    # Kiểm tra với tập dữ liệu lớn hơn
    processor = LegacyDataAnalyzerAdapter()
    data = list(range(1, 101))  # Từ 1 đến 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":
    # Kiểm tra toàn bộ quy trình với nhiều thao tác
    processor = LegacyDataAnalyzerAdapter()
    bar_visualizer = LegacyChartGeneratorAdapter("bar")
    line_visualizer = LegacyChartGeneratorAdapter("line")
    
    data = [12, 18, 25, 32, 28, 35, 42]
    
    # Tạo các hệ thống phân tích với những công cụ trực quan hóa khác nhau
    bar_system = AnalyticsSystem(processor, bar_visualizer)
    line_system = AnalyticsSystem(LegacyDataAnalyzerAdapter(), line_visualizer)
    
    # Chạy các phép phân tích
    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']}")
    
    # Lấy các phần tóm tắt
    print("Bar system summary:")
    print(bar_system.get_analysis_summary())
    print("Line system summary:")
    print(line_system.get_analysis_summary())
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Python online