Chương 9 — Adapter Pattern

Bài tập thực hành về adapter pattern

Bài tập 1: CSV Adapter

Mở rộng ứng dụng danh bạ đã xây dựng ở bài trước.

Thêm khả năng đọc từ file .csv với định dạng:

name,phone
Alice,123-456-7890
Bob,987-654-3210

Gợi ý:

import csv

class CSVContactsAdapter(FileReader):
    def __init__(self, filepath: str):
        self._filepath = filepath

    def get_contacts(self) -> list[Contact]:
        contacts = []
        with open(self._filepath, newline="") as f:
            reader = csv.DictReader(f)
            for row in reader:
                contacts.append(Contact(row["name"], row["phone"]))
        return contacts

Sau đó test với display_contacts() có sẵn.

Bài tập 2: Legacy Rectangle Adapter

Bài toán interface incompatibility

Có một thư viện cũ với interface:

class OldRectangle:
    def __init__(self, x1, y1, x2, y2):
        # x1,y1 = top-left; x2,y2 = bottom-right
        self._x1 = x1
        self._y1 = y1
        self._x2 = x2
        self._y2 = y2

    def get_area(self):
        width = self._x2 - self._x1
        height = self._y2 - self._y1
        return width * height

Hệ thống mới dùng interface:

from abc import ABC, abstractmethod

class Rectangle(ABC):
    @abstractmethod
    def draw(self, x, y, width, height):
        pass

Viết RectangleAdapter để:

  • Implement Rectangle interface
  • Dùng OldRectangle bên trong để tính diện tích
  • In ra thông tin khi draw() được gọi

Gợi ý:

class RectangleAdapter(Rectangle):
    def draw(self, x, y, width, height):
        old_rect = OldRectangle(x, y, x + width, y + height)
        area = old_rect.get_area()
        print(f"Drawing rectangle with area: {area}")

Câu hỏi để suy nghĩ:

  • Tại sao không sửa trực tiếp OldRectangle?
  • Khi nào nên tạo Adapter thay vì viết lại class?
Đăng ký nhận Newsletter
Cập nhật bài viết mới nhất!