Chương 10 — Strategy Pattern

Strategy pattern — giới thiệu

Strategy pattern là gì?

Key idea 1: Vấn đề với if-else phân nhánh

Xét một web scraper cần trích xuất dữ liệu từ nhiều nguồn:

class WebScraper:
    def scrape(self, source_type: str, data):
        if source_type == "xml":
            # parse XML...
        elif source_type == "sql":
            # query database...
        elif source_type == "csv":
            # read CSV...
        # ...thêm nữa

Khi có thêm loại nguồn mới, phải sửa trực tiếp class này. Hàm scrape() ngày càng dài, khó đọc, và dễ gây lỗi.

Đây là dấu hiệu cần áp dụng Strategy Pattern.

Key idea 2: Giải pháp — tách algorithm ra ngoài

Strategy Pattern đề xuất:

  • Tách mỗi thuật toán thành một class riêng biệt
  • Các class này đều implement cùng một interface
  • Đối tượng Context giữ một tham chiếu đến strategy hiện tại
  • Context có thể đổi strategy bất kỳ lúc nào
WebScraper (Context)
    |-- strategy: ExtractionStrategy
         |-- XMLExtractor
         |-- SQLExtractor
         |-- CSVExtractor

Key idea 3: Tính linh hoạt ở runtime

Strategy Pattern cho phép thay đổi behavior mà không cần sửa code của Context.

scraper = WebScraper()

scraper.set_strategy(XMLExtractor())
scraper.execute(xml_data)

scraper.set_strategy(SQLExtractor())
scraper.execute(sql_connection)

Cùng một scraper, nhưng behavior hoàn toàn khác nhau tùy vào strategy được set.

Key idea 4: Khi nào nên dùng Strategy?

Dùng Strategy khi:

  • Có nhiều biến thể của cùng một hành vi (sorting, extraction, rendering, payment…)
  • Cần thay đổi behavior tại runtime
  • Muốn tránh các khối if-else dài phân nhánh theo loại hành động
  • Muốn tách biệt logic của từng thuật toán để dễ test riêng

Ví dụ thực tế hay gặp:

  • Các phương thức thanh toán (PayPal, Credit Card, Bank Transfer)
  • Các thuật toán sắp xếp (QuickSort, MergeSort, BubbleSort)
  • Các chế độ nén file (ZIP, RAR, GZIP)
  • Các renderer (PDF, HTML, Markdown)
Đăng ký nhận Newsletter
Cập nhật bài viết mới nhất!