برای این که متوجه شویم Singleton Design Pattern برای حل چه مشکلی طراحی شده است، ابتدا سناریویی تعریف می کنیم. ما کلاسی نوشتهایم و میدانیم که آبجکت های متعددی ممکن است از روی این کلاس ساخته شود اما اگر بخواهیم به برنامه ی خود دستور دهیم که صرفاً یک آبجکت از روی کلاس مد نظرمان ساخته شود چه؟ به عبارت دیگر، این کلاس را محدود کنیم به یک شیء!
ممکن است این سؤال برای شما پیش بیاد که فایده ی این کار چیست؟ در پاسخ به این سؤال بایستی گفت که در بسیاری مواقع در کدنویسی، برای ما مواقعی پیش میآید که صرفاً به یک شیء از روی یک کلاس نیاز داریم مثلاً زمان هایی که یک کلاس داریم که مسئول نمایش صفحه ی اصلی اپلیکیشن است و ما صرفاً به یک صفحه ی اصلی بیشتر نیاز نخواهیم داشت پس چرا باید اجازه ی ساخت بیش از یک شیء از روی کلاس مسئول این کار را بدهیم؟ در واقع، وجود امکان ساخت بیش از یک شیء از روی این کلاس نه تنها ضرورتی ندارد حتی ممکن است منجر به بروز مشکل نیز گردد.
حال ممکن است شما با خود بگویید که ما بدون آن که کلاس مد نظر را محدود کنیم، میتوانیم خودمان یا سایر برنامه نویسان تیم را محدود به ساخت صرفاً یک آبجکت از روی این کلاس کنیم. در پاسخ به چنین رویکردی بایستی گفت درست است که چنین کاری امکانپذیر است، اما تضمینی برای عدم نقض آن وجود ندارد و ممکن است یکی از اعضای تیم توسعه ی نرمافزار به اشتباه اقدام به ساخت بیش از یک آبجکت از روی این کلاس نماید پس Best Practice آن است که از دیزاین پترنی که برای این کار طراحی شده است -سینگلتون- برای ساخت این کلاس استفاده نماییم.
دیزاین پترن سینگلتون این تضمین را ایجاد میکند که ما صرفاً یک آبجکت از روی یک کلاس خواهیم داشت و صرفاً یک راه برای دسترسی به آن آبجکت در سرتاسر نرمافزار وجود دارد. توجه داشته باشیم که این دیزاین پترن در زبانهای برنامه نویسی شیء گرای مختلف، به روشهای مختلفی پیادهسازی میشود لذا بسته به نوع زبانی که میخواهیم یاد بگیریم، می بایست از استایل خاصی برای پیادهسازی سینگلتون استفاده نماییم. به طور مثال، در این آموزش روش پیادهسازی سینگلتون در زبان برنامه نویسی جاوا را مورد بررسی قرار خواهیم داد:
public class MySingleton {
public myMethod() {
}
}
پیش از هر چیز، ابتدا یک کلاس میسازیم مثلاً تحت عنوان MySingleton. این کلاس میتواند حاوی Attribute ها و Method های مختلفی باشد به همان صورتی که تاکنون مورد استفاده قرار داده ایم. به طور مثال، متدی تحت عنوان ()myMethod در آن ایجاد کردهایم که مثلاً قرار است کار خاصی انجام دهد. با توجه به این که روش ایجاد این کلاس هیچ فرقی با روش معمولی ایجاد یک کلاس در زبان برنامه نویسی جاوا نمی کند، پس بالتبع خواهیم توانست دهها آبجکت از روی این کلاس بسازیم و این در حالی است که می بایست جلوی این کار را بگیریم. برای این منظور، کلاس خود را به صورت زیر تغییر خواهیم داد:
public class MySingleton {
private MySingleton { }
public myMethod() {
}
}
همانطور که در کد فوق مشاهده می شود، یک کانستراکتور از جنس private (خصوصی یا محدود) داخل کلاس مان ایجاد کردهایم که بدان معنا است که هیچ کسی از خارج از این کلاس قادر به ساخت آبجکتی از روی آن نخواهد بود و فقط خودمان آن هم از داخل این کلاس میتوانیم از رویش آبجتی بسازیم. حال ممکن است این سؤال پیش بیاد که با ایجاد این محدودیت اعمال شده توسط کانستراکتور، ما چگونه خواهیم توانست یک شیء از روی این کلاس ایجاد کنیم؟ در پاسخ به این سوال، می بایست دو کار انجام داد:
public class MySingleton {
private static MySingleton __me = null;
private MySingleton { }
public myMethod() {
}
}
همانطور که در کد فوق ملاحظه می شود، متغیری از جنس private و static تحت عنوان me__ ساختهایم که به منظور ظرفی برای نگهداری آبجکت کلاس MySingleton میباشد و مقدار اولیه ی آن را برابر با null یا «تهی» قرار دادهایم (توجه داشته باشیم که نام me__ کاملاً دلخواه است.) در ادامه، نیاز به ساخت یک متد جدید داریم و اینجا است که دیزاین پترن سینگلتون عملی خواهد شد:
public class MySingleton {
private static MySingleton __me = null;
private MySingleton { }
public static MySingleton getInstance()
{
if (__me == null) {
__me = new MySingleton();
}
return MySingleton;
}
public myMethod() {
}
}
همانطور که در کد فوق ملاحظه می شود، متدی تحت عنوان getInstance ساختهایم -البته هر نام دیگری نیز میتوان انتخاب کرد- که از جنس static است. به عبارت دیگر، فقط از داخل این کلاس میتوان آن را فراخوانی کرد. داخل این متد، یک دستور شرطی قرار دارد که داخل پرانتزهای دستور شرطی if چک کردهایم که اگر متغیر me__ تهی بود (برای مقایسه کردن دو چیز در اکثر زبانهای برنامه نویسی، از دو علامت == پشت سر هم استفاده می شود)، دستور داخل این شرط اجرا شود که عبارت است از مقداردهی کردن متغیر me__ با نمونهای از روی کانستراکتور و در نهایت هم این آبجکت را اصطلاحاً return خواهیم کرد یا بهتر بگوییم «به عنوان خروجی این متد در نظر خواهیم گرفت». حال اگر بخواهیم یک شیء از روی این کلاس بسازیم، به صورت زیر عمل خواهیم کرد:
MySingleton single = MySingleton.getInstance();
توجه داشته باشیم که تا وقتی که برنامه نیازی به آبجکتی از روی این کلاس نداشته باشد، آن آبجکت ساخته نخواهد شد اما به محض نیاز به این آبجکت، یکی ساخته شده اما اجازه ی ساخته شدن بیش یک بار داده نخواهد شد و در صورتی که در آینده بخش دیگری از نرمافزار نیاز به آبجکتی از روی این کلاس داشته باشد، آبجکت از پیش ساخته شده حاضر و آماده در اختیارش قرار خواهد گرفت! از این پس، به سادگی قادر خواهیم بود تا به متدهای کلاسی که این آبجکت از روی آن ساخته شده است دسترسی پیدا کنیم:
single.myMethod();