زمان تخمینی مطالعه: 7 دقیقه

الگوی Singleton را احتمالاً می‌توان پرکاربردترین الگوی طراحی و یکی از اصلی‌ترین زیر دسته‌های الگوهای طراحی ساختاری(Creational) دانست. الگوی Singleton به کاربر امکان می‌دهد اطمینان حاصل کند که یک کلاس فقط یک نمونه(instance) دارد، در حالی که یک نقطه دسترسی گلوبال به این نمونه ارائه می‌دهد. این الگو دارای یک ساختار ساده، آسان برای درک و استفاده می‌باشد. سادگی آن باعث شده که گاهی اوقات بیش از اندازه و در سناریوهایی که نیازی به آن نیست استفاده شود. در چنین مواردی، معایب استفاده از آن بیشتر از مزایایی است که به همراه دارد. به همین دلیل، گاهی اوقات الگوی Singleton را یک پادالگو(antipattern) یا الگوی تکی(pattern singleton) در نظر می‌گیرند.

Singleton pattern

بیان مسئله: الگوی Singleton دو مشکل را به طور همزمان حل می‌کند و اصل مسئولیت واحد(Single Responsibility Principle) را نقض می‌کند:

  1. اطمینان حاصل کنید که یک کلاس فقط یک نمونه دارد. چرا کسی باید بخواهد تعداد نمونه‌های یک کلاس را کنترل کند؟ رایج ترین دلیل این امر کنترل دسترسی به برخی از منابع مشترک است – به عنوان مثال، یک پایگاه داده یا یک فایل. نحوه کار به این صورت است که تصور کنید که یک شی ایجاد کرده‌اید، ولی پس از مدتی تصمیم به ایجاد یک شی جدید دارید. در این حالت به جای دریافت یک شیء جدید، شی‌ای را که قبلا ایجاد کرده‌اید مجددا دریافت خواهید کرد. توجه داشته باشید که اجرای این رفتار با یک سازنده(Constructor) معمولی غیرممکن است زیرا یک فراخوانی سازنده همیشه باید یک شی جدید را بر طبق طراحی خود برگرداند.
The global access to an object
  1. یک نقطه دسترسی سراسری(Global) به آن نمونه(نمونه تولیدی در مرحله اول) ارائه دهید. درست مانند یک متغیر سراسری، الگوی Singleton به شما امکان می‌دهد از هر کجای برنامه به برخی از شی‌ها دسترسی داشته باشید. با این حال، آن نمونه تولید شده را از بازنویسی شدن توسط کدهای دیگر نیز محافظت می‌کند.

نکته: امروزه الگوی Singleton آنقدر محبوب شده است که مردم ممکن است چیزی را Singleton بنامند حتی اگر فقط یکی از مشکلات ذکر شده را حل کند.

در حالت کلی تمام پیاده‌سازی‌های الگوی Singleton دارای دو مرحله مشترک هستند:

نکته: اگر کد شما به کلاس Singleton دسترسی دارد، می‌تواند متد Singleton را فراخوانی کند. بنابراین هر زمان که آن متد فراخوانی شود، همیشه همان شی برگردانده می‌شود.

نمونه قابل قیاس در دنیای واقعی

دولت هر کشور نمونه‌ای عالی از الگوی Singleton است. یک کشور می‌تواند تنها یک دولت رسمی داشته باشد. صرف نظر از هویت شخصی افراد تشکیل دهنده دولت، عنوان “دولت X” یک نقطه دسترسی جهانی است که گروهی از افراد مسئول را مشخص می‌کند.

ساختار الگوی Singleton

در این بخش به بررسی ساختار الگوی سینگلتون می‌پردازیم و پیاده‌سازی آن را به صورت UML خواهیم دید.

The structure of the Singleton pattern

کلاس Singleton متد static با نام getInstance را اعلام می‌کند که همان نمونه کلاس خود را برمی‌گرداند. بعلاوه سازنده Singleton باید از کد مشتری پنهان باشد و فراخوانی متد getInstance باید تنها راه دریافت شی Singleton باشد.

شبه کد(Pseudocode)

در این نمونه کد، کلاس اتصال پایگاه داده به عنوان Singleton عمل می‌کند. این کلاس سازنده عمومی ندارد، بنابراین تنها راه برای دریافت شیء آن فراخوانی متد getInstance است. این متد اولین شی ایجاد شده را گرفته و در تمام فراخوانی‌های بعدی آن را بر می‌گرداند.

 

// The Database class defines the `getInstance` method that lets
// clients access the same instance of a database connection
// throughout the program.
class Database is
    // The field for storing the singleton instance should be
    // declared static.
    private static field instance: Database

    // The singleton's constructor should always be private to
    // prevent direct construction calls with the `new`
    // operator.
    private constructor Database() is
        // Some initialization code, such as the actual
        // connection to a database server.
        // ...

    // The static method that controls access to the singleton
    // instance.
    public static method getInstance() is
        if (Database.instance == null) then
            acquireThreadLock() and then
                // Ensure that the instance hasn't yet been
                // initialized by another thread while this one
                // has been waiting for the lock's release.
                if (Database.instance == null) then
                    Database.instance = new Database()
        return Database.instance

    // Finally, any singleton should define some business logic
    // which can be executed on its instance.
    public method query(sql) is
        // For instance, all database queries of an app go
        // through this method. Therefore, you can place
        // throttling or caching logic here.
        // ...

class Application is
    method main() is
        Database foo = Database.getInstance()
        foo.query("SELECT ...")
        // ...
        Database bar = Database.getInstance()
        bar.query("SELECT ...")
        // The variable `bar` will contain the same object as
        // the variable `foo`.

قابلیت‌ها و کاربرد‌ها

نکته: همیشه می‌توانید این محدودیت را تنظیم کنید و اجازه ایجاد هر تعداد نمونه Singleton را بدهید. تنها کدی که نیاز به تغییر دارد، بدنه متد getInstance است.

نحوه پیاده‌سازی

  1. یک فیلد استاتیک خصوصی(private static) به کلاس برای ذخیره نمونه singleton اضافه کنید.
  2. یک روش ایجاد استاتیک عمومی برای به دست آوردن نمونه Singleton اعلام کنید.
  3. در داخل متد استاتیک، “مقدار دهی اولیه تنبل(lazy initialization)” را پیاده‌سازی کنید. این متد باید در اولین فراخوانی، یک شی جدید ایجاد کرده و آن را در فیلد استاتیک قرار دهد. متد همیشه باید آن نمونه را در تمام فراخوانی‌های بعدی برگرداند.
  4. سازنده کلاس را خصوصی کنید. متد استاتیک کلاس همچنان قادر خواهد بود سازنده را فراخوانی کند، اما سایر اشیاء را نه.
  5. روی کد کلاینت بروید و همه فراخوانی‌های مستقیم سازنده singleton را با فراخوانی‌های روش ایجاد استاتیک آن جایگزین کنید.

مزایا و معایب الگوی Singleton

این الگوی طراحی دارای مزایا و معایبی به شرح زیر است:

– مزایا

– معایب

ارتباط با الگوهای دیگر

نمونه کد الگوی Singleton

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *