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ó.
Thử thách
Trung bìnhTrong 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:
- 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) - 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) - 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 - Tạo một hệ thống hiện đại trong
modern_system.pysử 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())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
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTham số selfPhương thứcThuộc tínhPhương thức khởi tạo (__init__)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnHàm super()Ghi đè phương thứcKế thừa đa lớpThứ tự phân giải phương thứcÔn tập: hệ thống phân cấp nhân viên2Decorator
Giới thiệu về decoratorDecorator thuộc tínhDecorator phương thức tĩnhDecorator phương thức lớp5Tính đa hình
Xem lại cách ghi đè phương thứcKiểu gõ vịtLớp và phương thức trừu tượngThiết kế giao diệnÔn tập: máy tính hình học8Các khái niệm OOP nâng cao
Kết hợp và kế thừaMixinPhương thức tĩnh và phương thức lớpDecorator lớpTrình quản lý ngữ cảnh11Mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổng hợpTự luyện tập: Trình biên dịch Python online