Chương 6 — Singleton Pattern

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

Bài tập 1 — Sequence Number Generator

Tạo một Singleton implementation để sinh ra chuỗi số theo thứ tự. Yêu cầu:

  • Chỉ có một generator duy nhất trong toàn bộ chương trình.
  • Mỗi lần gọi get_next_number(), trả về số tiếp theo trong chuỗi, bất kể generator được lấy từ đâu.
  • Implement cả hai phiên bản: lazy instantiationeager instantiation.
  • So sánh: phiên bản nào hiệu quả hơn và tại sao?

Gợi ý cấu trúc:

class NumberGenerator:
    _instance = None
    _current_number = 0

    @classmethod
    def get_instance(cls):
        # Singleton logic ở đây
        pass

    def get_next_number(self):
        # Trả về số hiện tại và tăng lên 1
        pass

Bài tập 2 — Thread-Safe Number Generator

Mở rộng từ Bài tập 1:

  • Thêm thread safety vào implementation.
  • Câu hỏi cần suy nghĩ: Làm thế nào để test tính thread-safe?
  • Viết test code chạy 10-100 threads và xác nhận chuỗi số không bị gián đoạn.

Gợi ý test:

import threading

def test_thread_safe():
    generator = NumberGenerator.get_instance()
    print(generator.get_next_number())

threads = [threading.Thread(target=test_thread_safe) for _ in range(100)]
for t in threads:
    t.start()
for t in threads:
    t.join()
# Kết quả kỳ vọng: 0, 1, 2, ..., 99 không bị lệch thứ tự

Bài tập 3 — File Audit Manager

Tạo một Singleton ghi log vào file chung:

Yêu cầu:

  • File name có thể cấu hình (không hardcode).
  • Mỗi lần ghi, kèm theo timestamp tự động.
  • Mỗi message trên một dòng riêng.
  • Thread-safe.
  • Implement cả lazy và eager instantiation.

Gợi ý cấu trúc:

import datetime
import threading

class FileAuditManager:
    _instance = None
    _lock = threading.Lock()

    @classmethod
    def get_instance(cls, filename="audit.log"):
        with cls._lock:
            if cls._instance is None:
                cls._instance = cls.__new__(cls)
                cls._instance._open_file(filename)
        return cls._instance

    def _open_file(self, filename):
        self._file = open(filename, 'a')
        self._file.write(f"Log started at {datetime.datetime.now()}\n")

    def log_message(self, message):
        with self._lock:
            timestamp = datetime.datetime.now()
            self._file.write(f"{timestamp} - {message}\n")
            self._file.flush()

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

  • Lazy hay eager loading phù hợp hơn cho file audit? Tại sao?
  • Làm thế nào để đóng file khi chương trình kết thúc?
Đăng ký nhận Newsletter
Cập nhật bài viết mới nhất!