close up photo of programming of codes

codecungnhau.com

Một trang web về kỹ thuật lập trình

Python Design Pattern: Singleton

Singleton là một mẫu thiết kế khởi tạo, đảm bảo rằng chỉ có một đối tượng cùng kiểu tồn tại và cung cấp một điểm truy cập duy nhất vào nó cho bất kỳ mã nào khác.

Singleton có những ưu và nhược điểm gần giống như các biến toàn cục. Mặc dù chúng siêu tiện dụng, nhưng chúng phá vỡ tính mô đun của mã của bạn.

Cách sử dụng mẫu

Sử dụng: Rất nhiều nhà phát triển coi mẫu Singleton là một mẫu phản thiết kế mẫu. Đó là lý do tại sao việc sử dụng nó đang giảm trong mã Python.

Nhận biết: Singleton có thể được nhận dạng bằng một phương thức khởi tạo tĩnh, phương thức này trả về cùng một đối tượng được lưu trong bộ nhớ cache.

Singleton thơ ngây

Khá dễ dàng để triển khai một Singleton thơ ngây. Bạn chỉ cần ẩn hàm tạo và thực hiện một phương thức tạo tĩnh.

Việc này có thể không chính xác trong môi trường đa luồng. Nhiều luồng có thể gọi phương thức khởi tạo đồng thời và nhận một số thể hiện của lớp Singleton.

main.py

class SingletonMeta(type):
    """
    Lớp Singleton có thể được triển khai theo nhiều cách khác nhau trong Python. 
    Một số phương thức có thể bao gồm: lớp cơ sở, decorator, metaclass. 
    Chúng tôi sẽ sử dụng metaclass vì nó phù hợp nhất cho mục đích này.
    """
    _instances = {}
    def __call__(cls, *args, **kwargs):
        """
        Những thay đổi có thể xảy ra đối với giá trị của tham số __init__ 
        không ảnh hưởng đến thể hiện trả về.
        """
        if cls not in cls._instances:
            instance = super().__call__(*args, **kwargs)
            cls._instances[cls] = instance
        return cls._instances[cls]
class Singleton(metaclass=SingletonMeta):
    def some_business_logic(self):
        """
        Cuối cùng, bất kỳ singleton nào cũng phải xác định một số logic, 
        có thể được thực thi trên thể hiện của nó.
        """
        # ...
if __name__ == "__main__":
    # The client code.
    s1 = Singleton()
    s2 = Singleton()
    if id(s1) == id(s2):
        print("Singleton works, both variables contain the same instance.")
    else:
        print("Singleton failed, variables contain different instances.")

Kết quả:

Singleton works, both variables contain the same instance.

Singleton trong môi trường đa luồng

Để khắc phục sự cố phải đồng bộ hóa các luồng trong lần tạo đối tượng Singleton đầu tiên.

main.py

from threading import Lock, Thread
class SingletonMeta(type):
    """
    Đây là một triển khai an toàn trong môi trường đa luồng của Singleton.
    """
    _instances = {}
    _lock: Lock = Lock()
    """
     Một đối tượng khóa sẽ được sử dụng để đồng bộ hóa các luồng trong lần truy 
     cập đầu tiên vào Singleton.
    """
    def __call__(cls, *args, **kwargs):
        """
        Những thay đổi có thể có đối với giá trị của tham số __init__ không ảnh 
        hưởng đến thể hiện trả về.
        """
        # Hãy tưởng tượng rằng khi chương trình vừa được khởi chạy. Vì chưa 
        # có thể hiện Singleton, nhiều luồng có thể đồng thời vượt qua điều 
        # kiện  trước đó và đến chỗ này gần như cùng một lúc. Luồng đầu tiên  
        # trong số chúng sẽ nhận được khóa và sẽ tiếp tục, trong khi những  
        # luồng còn lại sẽ đợi ở đây.
        with cls._lock:
            # Luồng đầu tiên có được khóa, đến điều kiện này, đi vào bên 
            # trong và tạo thể hiện Singleton. Sau khi nó rời khỏi khối khóa,  
            # một luồng có thể đang chờ giải phóng khóa sau đó có thể đi 
            # vào phần này. Nhưng vì thể hiện đã được khởi tạo nên 
            # luồng sẽ không tạo đối tượng mới.
            if cls not in cls._instances:
                instance = super().__call__(*args, **kwargs)
                cls._instances[cls] = instance
        return cls._instances[cls]
class Singleton(metaclass=SingletonMeta):
    value: str = None
    """
    Ta sẽ sử dụng thuộc tính này để kiểm tra sự hoạt động của Singleton.
    """
    def __init__(self, value: str) -> None:
        self.value = value
    def some_business_logic(self):
        """
        Cuối cùng, bất kỳ singleton nào cũng phải xác định một số logic, 
        có thể được thực thi trên thể hiện của nó.
        """
def test_singleton(value: str) -> None:
    singleton = Singleton(value)
    print(singleton.value)
if __name__ == "__main__":
    # The client code.
    print("If you see the same value, then singleton was reused (yay!)\n"
          "If you see different values, "
          "then 2 singletons were created (booo!!)\n\n"
          "RESULT:\n")
    process1 = Thread(target=test_singleton, args=("FOO",))
    process2 = Thread(target=test_singleton, args=("BAR",))
    process1.start()
    process2.start()

Kết quả:

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)
RESULT:
FOO
FOO

Đã đăng vào

trong

,

bởi

Bình luận

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *