آشنایی با دیزاین پترنی تحت عنوان سینگلتون


برای این که متوجه شویم 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();
لیست نظرات
کاربر میهمان
دیدگاه شما چیست؟
کاربر میهمان
majid
majid
private static ConnectionManager Instance = null;
سلام اگر میشه یک توضیح در مورد این کد سینگل تون بدین

package mainlibrary;

import java.sql.*;

public class ConnectionManager {


private static ConnectionManager Instance = null;
private final String username ="root";
private final String password ="";
private final String m_conn_manager ="jdbc:mysql://localhost:3306/library";


private Connection conn =null;

public ConnectionManager() {
}


//singletone اجازه ساخت شی بر روی کلاس را نمی دهد




public static ConnectionManager getInstance() {
if(Instance ==null){
Instance =new ConnectionManager();

}
return Instance;
}


private boolean openconnection(){
try {
conn =DriverManager.getConnection(m_conn_manager,username,password);
return true;
} catch (Exception e) {
return false;
}
}


public Connection getConnection(){
if(conn==null){
if(openconnection()){
System.out.println("openconnection !..");
return conn;
}else{
return null;
}
}
return conn;
}


public void close(){
try {
conn.close();
conn=null;

} catch (Exception e) {
System.err.println(e);
}


}

}
این هم کل کد هست
امیر
امیر
...اما اجازه ی ساخته شدن بیش (از) یک بار داده نخواهد ...
pooya
pooya
با عرض سلام و خسته نباشید خدمت شما
اول میخاستم یه تشکر کنم بابت سایت واقعا عالیتون که انقد کامل همه چیو توضیح داده .
و دوم اینکه میخاستم بگم من یه مشکلی دارم وقتی که مطالب سایت رو میخونم چیز زیادی متوجه نمیشم و همش به امید اینکه بعدا که جلو تر برم این مطالب برام جا میافته همینجوری میخونم و میرم جلو از اونجایی که علاقی زیاید به برنامه نویسی دارم و امکان حضور توی کلاس هم برام وجود نداره فقط تونستم یه ترم سی پلاس پلاس مقدماتی رو گذروندم اما با این حال بازم مطالبی که از سایتتون میخونم تا حد زیادی برام نا مفهومه و از این رو خیلی نگرانم که نتونم از چالشای پیش روم بر بیام میخاستم ببینم این چیزی که میگم واسه کسی که تو سطح منه طبیعیه یا اینکه مشکل از طرف خودمه و باید با دقت تر جلو برم؟! هر چند که الا هم تمام سعیم رو میکنم تا اروم اروم و با تمام دقت جلو برم
واقعا نگرانم از این بابت ممنون میشم اگه کمکی هست کمک کنید تا بتونم از همین اول راه صحیح راهمو برم.
ببخشید طولانی شد ممنون میشم اگه پاسخ بدین .
با تشکر.
کاربر میهمان
فرشیدمن یک کاربر مهمان هستم
سلام
در خط 12 باید me__ خروجی باشه به جای MySingleton
کاربر میهمان
هادیمن یک کاربر مهمان هستم
سلام
در خط 12 بجای __me نوشته شده MySingleton
کاربر میهمان
nasrinمن یک کاربر مهمان هستم
MySingleton __me ظرف نگهداری object ایجاد شده است و اگر null بودن آن بررسی نشود و شی جدید ایجادشود که singleton معنی ندارد در حالی که قرار است فقط یک شی ساخته شود و اگر برنامه مجددا نیاز به شی داشت از همان شی قبلی استفاده شود.
ccc ccc
ccc ccc
سلام. بهتر بود متد getInstance فقط آبجکت و برگردونه و نیازی به بررسی null بودنش نیست. تو هون خط اول آبجکت و می‌ساختین.
امیر
امیر
سلام
خط23 یا بگیریم -------> یاد بگیریم
با تشکر
کاربر میهمان
ایمانمن یک کاربر مهمان هستم
سلام و عرض خسته نباشید، امکانش هست این متن را روشن سازی کنید ؟ منظور از استاتیک چی هست ؟ همان‌طور که در کد فوق ملاحظه می شود، متدی تحت عنوان getInstance ساخته‌ایم -البته هر نام دیگری نیز می‌توان انتخاب کرد- که از جنس static است. به عبارت دیگر، فقط از داخل این کلاس می‌توان آن را فراخوانی کرد.
محمود حسن زاده
محمود حسن زاده
سلام، سوالی که برام پیش اومده اینه که ایا static مشخص کننده سطح دسترسیه یا نه؟ اگه نیستش پس چرا در مورد متد getinstance شما گفتین وقتی از نوع static باشه فقط از داخل این کلاس می‌توان آن را فراخوانی کرد و اگه هستش پس public و private چه نقشی دارن؟ یعنی مفهوم static رو کامل متوجه نشدم؟ ممنون میشم اگه راهنماییم کنین