معرفی و پیاده سازی دیزاین پترن سینگلتون در اندروید

دیزاین پترن سینگلتون چیست؟

دیزاین پترن سینگلتون یک creational design pattern است ؛ این الگو تضمین میکند که یک کلاس فقط یک نمونه (Instance) داشته باشد و دسترسی به این نمونه فقط از طریق یک نقطه دسترسی همگانی (global point of access) امکان پذیر است . به عبارت ساده‌تر . هر زمان که چندین کلاس برای کلاس مورد نظر درخواست کنند ، همان نمونه کلاس را دریافت می کنند.

سینگلتون دو کار را همزمان انجام می‌دهد .

۱) اطمینان حاصل میکند که یک کلاس فقط یک نمونه دارد.

چرا کسی میخواهد تعداد نمونه یک کلاس را کنترل کند؟

مهمترین دلیل این امر کنترل دسترسی به برخی از منابع مشترک است. به عنوان مثال پایگاه داد یک منبع مشترک است .

نحوه کار به این صورت است : تصور کنید که شما یک شی (object) جدید ایجاد کردید اما بعد از مدتی تصمیم میگیرید یک شی جدید دریافت کنید؛ به جای دریافت شی جدید ، شی که قبلا ایجاد کرده‌اید دریافت خواهید کرد

توجه داشته باشید که این رفتار با سازنده (constructor) معمولی امکان پذیر نیست . زیرا فراخوانی سازنده باعث ایجاد یک شی جدید میشود.

۲) ارایه دادن یک نقطه دسترسی همگانی به نمونه

متغیرهای همگانی(global variables) اگرچه خیلی مفید هستند اما بسیار نا امن هستند زیرا هر کدی میتواند محتوای آن متغییرها را رونویسی کرده و برنامه را خراب کند.

درست مثل یک متغییرهمگانی ، الگوی سینگلتون به شما این امکان را می‌دهد که از هرجای برنامه به برخی از اشیا دسترسی پیدا کنید با این حال همچنین از این نمونه در برابر رونویسی توسط کدهای دیگر محافظت می‌کند.

چه زمانی از سینگلتون استفاده کنیم؟

  • از این الگو زمانی استفاده کنید که یک کلاس در برنامه شما باید فقط یک نمونه در دسترس سایر کلاسها قرار دهد . به عنوان مثال یک شی پایگاه داده که توسط قسمت‌های مختلف برنامه قرار است به اشتراک گذاشته شود.
  • هنگامی که به کنترل دقیق‌تر متغیرهای همگانی نیاز دارید از این الگو استفاده کنید.

نحوه پیاده سازی سینگلتون :

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

۱ ) سازنده (constructor) پیش فرض را private کنید تا سایر اشیا نتوانند از کلاس سینگلتون استفاده مجدد کنند( به عبارت بهتر نتوانند شی جدید بسازند) .

۲) یک متد استاتیک ایجاد کنید که به عنوان سازنده (constructor) عمل کند. این متد ، سازنده (private constructor) را برای ایجاد یک شی فراخوانی میکند و آن را در یک فیلد استاتیک ذخیره میکند؛ تمام فراخوانی‌هایی که به این متد می‌شود شی ذخیره شده را برمیگرداند .

مثال ۱ ) پیاده سازی سینگلتون :

پیاده سازی این الگو بسیار آسان است. قطعه کد زیر نحوه ایجاد Singleton را نشان می دهد.

   public class Singleton  {  

      private static Singleton INSTANCE = null;

       private Singleton() {};   

              public static Singleton getInstance() {
                   if (INSTANCE == null) {
                        INSTANCE = new Singleton();
                   }
              return(INSTANCE);
              }
   }


مثال ۲) نحوه ایجاد نمونه واحد برای Retrofit :

 public class RetrofitClient {   
      private static Retrofit retrofit = null;   

      private RetrofitClient() {}    

            public static Retrofit getClient(String baseUrl) {
                  if (retrofit==null) { 
                          retrofit = new Retrofit.Builder()
                          .baseUrl(baseUrl) 
                           .addConverterFactory(GsonConverterFactory.create())
                          .build();
                  } 
           return retrofit;
           }
 }


توجه : مشکل اصلی این نوع پیاده سازی این است که thread safe نیست. یعنی دو ترد همزمان میتوانند یک نمونه جدید برای کلاس ایجاد کنند . برای حل این مشکل بهتر است سینگلتون را به صورت زیر پیاده سازی کنیم.

 public class RetrofitClient {

       private static volatile Retrofit retrofit = null;

       private RetrofitClient() {}   

            public static Retrofit getClient(String baseUrl) {
                  if (retrofit==null) {
                          synchronized (RetrofitClient.class) {
                          retrofit = new Retrofit.Builder()
                          .baseUrl(baseUrl)
                          .addConverterFactory(GsonConverterFactory.create())
                          .build();
                          }
                  }     
             return retrofit;
            }
 }