حوزه: Object
هدف: Creational
حالتی را در نظر بگیرید که کلاسی دارید که میخواهید در کل برنامه خود فقط یک شی از این کلاس ساخته شود و اجازه ساخته شدن نمونه جدید به استفاده کنندگان از این کلاس داده نشود. این عمل در مواقعی بسیار لازم و ضروری است. به طور مثال حالتی را درنظر بگیرید که در برنامه کلاسی وجود دارد که واسط تنظیمات برنامه است یعنی برنامه هنگام لود شدن تنظیمات خود را در آن بارگزاری میکند. حال اگر این شی یک شی در کل برنامه یکتا نباشد و هر بخش از برنامه که بخواهد تنظیمات را بخواند و یا تغییری در آن ایجاد کند مجبور باشد که یک شی جدید از کلاس تنظیمات بسازد مدیریت این اشیا مشکل میشود و همچنین باعث نابه سامانی در تنظیمات خواهد شد. راه حل این مسئله این است که از همان اول کلاس به گونه ای تعریف شود که اجازه ساختن نمونه جدید به کاربران ندهد و تنها کاربران بتوانند یک نمونه از کلاس به وجود آورند. اگر به برخی از قسمتهای سیستم عامل ویندوز هم نگاهی بکنیم متوجه میشویم که چنین مکانیزمی در آن تعبیه شده است مثلاً یک سیستم فایل برای مدیریت فایلها وجود دارد و یا با وجود این که ممکن است چندین پرینتر به کامپیوتر متصل باشد ولی فقط یک printer spooler در سیستم وجود دارد. برای به وجود آوردن چنین مکانیزمی شاید اولین راه حل این باشد که یک شی سراسری در کل برنامه تعریف شده و هروقت که برنامهای بخواهد از این کلاس استفاده کند از شی سراسری تعریف شده استفاده کند. اما مشکلی که این راه حل دارد این است که این راه حل مانع ساخت شی جدید از کلاس نمیشود. یک راه حل بهتر این است که خود کلاس را مسئول این کار قرار دهیم که مواظب باشد که یک نمونه بیشتر نداشته باشد. این کار را الگوی Singleton انجام میدهد.
طراحی الگو
روش کار این الگو به این صورت است که یک نمونه از خود کلاس در داخل کلاس ساخته میشود و هر وقت که کلاسهای دیگر خواستند از این کلاس استفاده کنند تنها میتوانند به این نمونه ساخته شده دسترسی داشته باشند و نمیتوانند از کلاس نمونه سازی کنند.
ساختار این الگو به این شکل است:
همانطور که در شکل میبینید یک فیلد به نام instance داریم که از خود کلاس است و این فیلد تنها الگویی که قرار است ساخته شود را در خود نگهداری میکند. سازنده(constructor) این کلاس از نوع private بوده بنابراین نمیتوان از این کلاس یک نمونه جدید توسط عملگر new ایجاد کرد. تنها راه ساختن یک نمونه از این کلاس فراخوانی متد getInstance است.
ویژگی های این الگو
این الگو باعث میشود که دسترسی به نمونههای کلاس کنترل شود و تعداد خاص از نمونه ها ایجاد شود. همچنین با استفاده از این الگو نیاز به ساختن متغیرهای سراسری کمتر شده و از اشغال فضا توسط متغیرهای سراسری جلوگیری میکند.
پیاده سازی، مثال:
حال اگر نیاز باشد که از یک خانواده کلاس ها تنها یک نمونه ایجاد شود پیاده سازی این الگوی کمی متفاوت تر خواهد شد. برای مثال تصور کنید که یک کلاس میوه دارید که از آن کلاسهای دیگری مانند سیب و پرتقال مشتق شدهاند و لازم است که در برنامه فقط یک عدد میوه وجود داشته باشد یعنی اگر یک سیب وجود دارد دیگر نتوان میوهی دیگری(چه سیب و چه پرتقال) ایجاد کرد. به منظور پیاده سازی چنین روشی به شکل زیر عمل میکنیم.
الگوهای مرتبط با الگوی Singleton الگوهای Facade و Abstract Factory و بسیاری از الگوهای دیگر هستند که لازم است در برنامه از آنها فقط یک نمونه ساخته شده باشند که در زمان معرفی این الگوها توضیحات لازم ارایه خواهد شد.
همانطور که در شکل میبینید یک فیلد به نام instance داریم که از خود کلاس است و این فیلد تنها الگویی که قرار است ساخته شود را در خود نگهداری میکند. سازنده(constructor) این کلاس از نوع private بوده بنابراین نمیتوان از این کلاس یک نمونه جدید توسط عملگر new ایجاد کرد. تنها راه ساختن یک نمونه از این کلاس فراخوانی متد getInstance است.
ویژگی های این الگو
این الگو باعث میشود که دسترسی به نمونههای کلاس کنترل شود و تعداد خاص از نمونه ها ایجاد شود. همچنین با استفاده از این الگو نیاز به ساختن متغیرهای سراسری کمتر شده و از اشغال فضا توسط متغیرهای سراسری جلوگیری میکند.
پیاده سازی، مثال:
public class Singleton {همانطور که درکد مشاهده میشود یک بار یک نمونه از کلاس ساخته میشود و تنها راه دسترسی به کلاس استفاده از ویژگی getInstance میباشد که نمونه ساخته شده را برمیگرداند. در این نوع پیاده سازی از همان ابتدا یک نمونه از کلاس ساخت شده است و استفاده میشود ولی می توان این نمونه را وقتی ساخت که درخواستی برای اولین بار به کلاس ارسال شود که به این شیوه Lazy instantiate گفته میشود. کد این روش به شکل زیر است.
private Singleton() {
}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
public class SingletonL {کدی که آورده شده است تا حدی میتواند هدف این الگو را که ساخته شدن یک نمونه از کلاس باشد را برآورده کند ولی اگر برنامه دارای چند thread باشد ممکن است در مواردی بیشتر از یک نمونه از کلاس ساخته شود که در اصطلاح گفته میشود برنامه Thread Safe نیست که به جای کد بالا از کد پایین استفاده میکنیم.
private SingletonL instance = null;
private SingletonL() {
}
public SingletonL getInstance() {
if (instance == null)
instance = new SingletonL();
return instance;
}
}
public class SingletonTSL {کد بالا علاوه بر Thread safe بودن خاصیت Lazy instatiate هم دارد.
private SingletonTSL instance = null;
private SingletonTSL() {
}
public SingletonTSL getInstance() {
if (instance == null) {
synchronized (SingletonTSL.class) {
if (instance == null)
instance = new SingletonTSL();
}
}
return instance;
}
}
حال اگر نیاز باشد که از یک خانواده کلاس ها تنها یک نمونه ایجاد شود پیاده سازی این الگوی کمی متفاوت تر خواهد شد. برای مثال تصور کنید که یک کلاس میوه دارید که از آن کلاسهای دیگری مانند سیب و پرتقال مشتق شدهاند و لازم است که در برنامه فقط یک عدد میوه وجود داشته باشد یعنی اگر یک سیب وجود دارد دیگر نتوان میوهی دیگری(چه سیب و چه پرتقال) ایجاد کرد. به منظور پیاده سازی چنین روشی به شکل زیر عمل میکنیم.
public class SingleFruit {با توجه به کد بالا اگر به کلاسهای فرزندان مقداردهی نشده باشد استفاده از کلاس پدر باعث خطای NullReference خواهد شد و همچنین این کد Thread safe نمیباشد.
public String name;
protected SingleFruit() {
}
protected static SingleFruit instance;
public static SingleFruit getInstance() {
return instance;
}
}
public class SingleApple extends SingleFruit {
private SingleApple() {
name = "Apple";
}
public static SingleFruit getInstance() {
if (instance == null)
instance = new SingleApple();
return instance;
}
}
public class SingleOrange extends SingleFruit {
private SingleOrange() {
name = "Orange";
}
public static SingleFruit getInstance() {
if (instance == null)
instance = new SingleOrange();
return instance;
}
}
الگوهای مرتبط با الگوی Singleton الگوهای Facade و Abstract Factory و بسیاری از الگوهای دیگر هستند که لازم است در برنامه از آنها فقط یک نمونه ساخته شده باشند که در زمان معرفی این الگوها توضیحات لازم ارایه خواهد شد.
مثال پیاده سازی شده با زبان جاوا را میتوانید از github من دانلود کنید.
اگر قبلا در بیان ثبت نام کرده اید لطفا ابتدا وارد شوید، در غیر این صورت می توانید ثبت نام کنید.