چگونه می‌توان از الگوی Singleton در برنامه‌ها استفاده کرد

خلاصه
1404/05/26

الگوی Singleton یک الگوی طراحی است که اطمینان می‌دهد یک کلاس فقط یک نمونه از خود ایجاد کند و یک نقطه دسترسی سراسری به آن نمونه فراهم کند. این الگو برای مواردی مناسب است که دقیق

چگونه می‌توان از الگوی Singleton در برنامه‌ها استفاده کرد

الگوی Singleton یک الگوی طراحی است که اطمینان می‌دهد یک کلاس فقط یک نمونه از خود ایجاد کند و یک نقطه دسترسی سراسری به آن نمونه فراهم کند. این الگو برای مواردی مناسب است که دقیقاً یک نمونه از یک کلاس مورد نیاز است تا رفتاری هماهنگ در سراسر سیستم داشته باشیم، مانند مدیریت تنظیمات، لاگینگ، یا اتصال به یک پایگاه داده.

در اینجا چند روش برای پیاده‌سازی و استفاده از الگوی Singleton در برنامه‌ها وجود دارد:

**1. پیاده‌سازی ساده (غیر Thread-Safe):**

این پیاده‌سازی ساده‌ترین شکل است، اما در محیط‌های چند نخی (Multithreaded) ممکن است مشکل‌ساز شود.

```python
class Singleton:
_instance = None

def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance

# استفاده
s1 = Singleton()
s2 = Singleton()

print(s1 is s2) # خروجی: True
```

**توضیحات:**

* `_instance`: یک متغیر کلاس برای نگهداری نمونه تکین. مقدار اولیه `None` است.
* `__new__(cls, *args, **kwargs)`: این متد قبل از `__init__` فراخوانی می‌شود و مسئول ایجاد نمونه کلاس است.
* در داخل `__new__`، ابتدا بررسی می‌کنیم که آیا `_instance` مقدار دارد یا نه. اگر `None` باشد (یعنی هنوز نمونه‌ای ایجاد نشده است)، با استفاده از `super().__new__(cls, *args, **kwargs)` یک نمونه جدید ایجاد می‌کنیم و آن را در `_instance` ذخیره می‌کنیم.
* در نهایت، `_instance` را برمی‌گردانیم.

**مشکل Thread-Safety:**

در محیط‌های چند نخی، ممکن است دو نخ به طور همزمان به خط `if not cls._instance:` برسند، هر دو تشخیص دهند که نمونه‌ای وجود ندارد و هر دو سعی کنند یک نمونه جدید ایجاد کنند، که این باعث نقض الگوی Singleton می‌شود.

**2. پیاده‌سازی Thread-Safe با استفاده از Lock:**

برای حل مشکل Thread-Safety، می‌توانیم از یک Lock (قفل) استفاده کنیم تا فقط یک نخ در یک زمان بتواند بخش بحرانی کد را اجرا کند (یعنی بخشی که نمونه را ایجاد می‌کند).

```python
import threading

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

def __new__(cls, *args, **kwargs):
with cls._lock:
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance

# استفاده
s1 = Singleton()
s2 = Singleton()

print(s1 is s2) # خروجی: True
```

**توضیحات:**

* `_lock = threading.Lock()`: یک شی قفل ایجاد می‌کنیم.
* `with cls._lock:`: با استفاده از دستور `with`، یک بلوک قفل ایجاد می‌کنیم. وقتی یک نخ وارد این بلوک می‌شود، قفل را می‌گیرد و نخ‌های دیگر باید منتظر بمانند تا قفل آزاد شود. وقتی نخ از بلوک خارج می‌شود، قفل به طور خودکار آزاد می‌شود.

**3. پیاده‌سازی Thread-Safe با استفاده از Double-Checked Locking:**

این روش یک بهینه‌سازی است که ابتدا بدون قفل بررسی می‌کند که آیا نمونه‌ای وجود دارد یا نه. اگر نمونه‌ای وجود ندا