نمایش نتایج 1 تا 17 از 17

نام تاپیک: ساختار الگوی Singleton

  1. #1

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

    سلام
    من اینجا یه اشتباهی مییبینم، شما هم میبینید؟ یا اصلاً اشتباه میبینم :|

    Capture.jpg

  2. #2

    نقل قول: ساختار الگوی Singleton

    سلام.
    منظورتون رو از اشتباهی که می‌بینید واضح بگید که باهم بررسیش کنیم. یه مثال ساده از الگوی Singleton هست و تضمین می‌کنه که فقط و فقط یک نمونه از این کلاس ساخته خواهد شد.

    دوتا اشکال من در این کد می‌بینم. یکی در متد getInstance رخ داده که باید me__ رو برمی‌گردوند. توی متد someMethod هم با استفاده کردن از توضیح تک خطی کل اون خط تبدیل به متن توضیحی می‌شه که نویسنده‌ی این کد حواسش بشون نبوده. صلاحیت چنین فردی واسه آموزش دادن الگوی Singleton اونم در فضای مجازی زیرسؤاله!
    public class MySingleton {
    // placeholder for current singleton object
    private static MySingleton __me = null;
    // private constructor - now no other object can instantiate
    private MySingleton() { }
    // this is how you ask for the singleton
    public static MySingleton getInstance() {
    // do I exist?
    if ( __me == null ) {
    // if not, instantiate and store
    __me = new MySingleton();
    }
    return __me;
    }

    // additional functionality
    public /* EDIT: */ void someMethod() { /* ... */ }
    }



    نکته: بهتره موقع قرار دادن کد از تگ کد جاوا استفاده کنید و از کد مورد نظرتون عکس نگیرید. اینجوری هم یکپارچگی انجمن حفظ می‌شه و هم برای افرادی که احتمالا در آینده اینجا رو بخونن مفید خواهد بود.
    آخرین ویرایش به وسیله محمد فدوی : سه شنبه 01 اردیبهشت 1394 در 22:15 عصر
    اگر به بهداشت و سلامت حیوانات علاقه دارید، از vetMD.ir دیدن کنید.
    وبلاگ شخصی من: fadavi.net

    اینجا کمتر سر می‌زنم. (تلگرام من)

  3. #3
    مدیر بخش آواتار dasssnj
    تاریخ عضویت
    مرداد 1391
    محل زندگی
    Esfahan
    پست
    1,022

    نقل قول: ساختار الگوی Singleton

    برای اون متد someMethod هم اگه یه نوع بازگشتی یا void تعریف می کرد قابل قبول تر بود ، الان مثل کانستراکتور می مونه

    Write Once, Run Anywhere

  4. #4

    نقل قول: ساختار الگوی Singleton

    نقل قول نوشته شده توسط محمد فدوی مشاهده تاپیک
    یکی در متد getInstance رخ داده که باید me__ رو برمی‌گردوند.
    آفرین منظورم همین بود :) خواستم مطمئن بشم که اشتباه از طرف ایشونه.

    نقل قول نوشته شده توسط محمد فدوی مشاهده تاپیک
    صلاحیت چنین فردی واسه آموزش دادن الگوی Singleton اونم در فضای مجازی زیرسؤاله!
    ولی صداش عالیه، انگاری داره فارسی حرف میزنه.

    نقل قول نوشته شده توسط محمد فدوی مشاهده تاپیک
    نکته: بهتره موقع قرار دادن کد از تگ کد جاوا استفاده کنید و از کد مورد نظرتون عکس نگیرید. اینجوری هم یکپارچگی انجمن حفظ می‌شه و هم برای افرادی که احتمالا در آینده اینجا رو بخونن مفید خواهد بود.
    چشم :) میخواستم بی واسطه نشون بدم همراه با آرم موسسش، البته داخل سایت ضمیمه کردمش.

  5. #5
    کاربر دائمی آواتار -سیّد-
    تاریخ عضویت
    فروردین 1393
    محل زندگی
    تهران
    پست
    233

    نقل قول: ساختار الگوی Singleton

    در ضمن این کلاس الان thread-safe نیست. اگه بخواد باشه، باید synchronization رعایت بشه:

    public static syncrhonized MySingleton getInstance() {

    // do I exist?

    if ( __me == null ) {

    // if not, instantiate and store

    __me = new MySingleton();

    }

    return __me;

    }


    یا از اون بهتر و با performance بالاتر:

    private static final Object _lock = new Object();
    public static MySingleton getInstance() {

    // do I exist?

    if ( __me == null ) {
    synchronized (_lock) {
    if (__me == null) {

    // if not, instantiate and store

    __me = new MySingleton();
    }
    }

    }

    return __me;

    }


  6. #6
    [younes]
    مهمان

    نقل قول: ساختار الگوی Singleton

    اگر ممکنه یکی بگه singleton چیه و به چه کاري میاد؟

  7. #7
    کاربر دائمی آواتار -سیّد-
    تاریخ عضویت
    فروردین 1393
    محل زندگی
    تهران
    پست
    233

    نقل قول: ساختار الگوی Singleton

    نقل قول نوشته شده توسط [younes] مشاهده تاپیک
    اگر ممکنه یکی بگه singleton چیه و به چه کاري میاد؟
    Singleton یک Design Pattern هست که توسط اون کلاسی ساخته می‌شه که تضمین می‌شه که تنها یک instance از اون وجود داره، و همه‌ی بخش‌های کد به اون به راحتی دسترسی دارن. یه مثالش connection به یه سیستم دیگه هست (مثل پایگاه داده). یعنی اگه شما می‌خواین تضمین کنید که توی برنامه‌تون تنها و تنها یک connection به یه سرویس خاص وجود داره، می‌تونید برای اون connection یه کلاس Singleton بنویسید.
    روشش هم به این صورت هست که سازنده‌ی کلاس رو private می‌کنید (در نتیجه هیچ کس به جز متدهای static خود کلاس نمی‌تونه ازش شیء بسازه) و یک نمونه‌ی static از این کلاس داخل خودش می‌سازید، و یک متد getInstance تعریف می‌کنید (static) که این نمونه رو برمی‌گردونه. در نتیجه تنها یک نمونه از کلاس شما ساخته شده و به همه برگردونده می‌شه، و از همه جای کد به راحتی می‌شه این تابع static رو فراخوانی کرد و به نمونه‌ی ساخته شده دسترسی پیدا کرد. یعنی نیازی نیست که یک پارامتر از نوع این کلاس به این طرف و اون طرف بفرستید و هر کسی نیاز داشته باشه، می‌تونه از طریق این تابع static بهش دسترسی پیدا کنه.
    خوب از این توضیح آخری که دادم، مشخص می‌شه که Singleton خیلی مشابهت داره با متغیرهای global. در نتیجه همون بحث‌ها و مشکلاتی که استفاده از متغیرهای global به وجود میاره، استفاده از Singleton هم به وجود میاره (البته Singleton خیلی بهتر از متغیرهای global هست).

    توضیحات کامل در ویکیپدیا:
    https://en.wikipedia.org/wiki/Singleton_pattern

    پ.ن. یه اشکال دیگه توی کد مورد نظر (که حواسم بهش نبود) اینه که متغیر me__ باید volatile باشه. توضیح کاملتر در مورد volatile:
    http://stackoverflow.com/questions/1...eyword-in-java
    http://www.javamex.com/tutorials/syn...volatile.shtml

    پ.ن.۲. توی مثال دومی که زدم، اون روشی که synchronized رو اورده بودم داخل if، اسمش هست Double-checked locking:
    https://en.wikipedia.org/wiki/Double-checked_locking

  8. #8
    کاربر دائمی آواتار ahmad.mo74
    تاریخ عضویت
    مرداد 1393
    محل زندگی
    تهران
    پست
    437

    نقل قول: ساختار الگوی Singleton

    سلام

    علاوه بر توضیحات دوستمون یه سری نکات رو هم من بگم.

    درباره design pattern ها بهترین توضیحات رو میتونید از کتاب Gang of Four بخونید.

    موارد استفاده singleton خیلی زیاده. اما بعضی جاها استفادش بی مورده که اصطلاحا بهش anti-pattern میگن.

    یه مورده استفاده خوب از singleton object ها، توی معماری mvc ه. مثلا در لایه model یه سری کلاس داری که وظایفی مثل CRUD رو برای هر entity انجام میدن.

    فرض کنیم قراره در هر ثانیه هزاران نفر درخواست بفرستن به سرور و یه رکورد از یه تیبلی رو بخوان. اونوقت شما میای هربار اون کلاسی که وظیفش گرفتن آبجکت از دیتابیسه رو new میکنی و بقیه ماجرا...
    خب اینجا یه فاجعه رخ میده، یعنی؛ به ازای هر درخواست، یبار new کردن یه آبجکت نسبتا سنگین.

    پس بهتره که اون آبجکت singleton باشه. اما singleton بودن هم مشکلات خاص خودشو داره.
    یکیش thread-safe بودنه.

    یه راه خیلی بدش اینه که بیای توابعت رو synchronized تعریف کنی و برای دسترسی متغیرها lock بزاری و ...
    اما راه خیلی بهترش اینه که اون کلاس رو به صورت stateless پیاده کنی.

    برای اینکه کلاسی رو stateless کنی، باید تمامی property های سطح کلاس رو حذف کنی (به جز مواردی که مشکل ساز نمیشه). یعنی هیچ چیز مشترکی بین thread هایی که قراره از اون آبجکت singleton استفاده کنن نباشه.
    مثلا دوتا ترد همزمان بیان اون آبجکت singleton رو بگیرن و یه چیزی رو تغییر بدن!

    در کل چنین کلاسی فقط باید دارای متد باشه.

    اما شاید یکی بگه خب اگه قرار باشه یه آبجکت بین همه ترد ها شیر بشه که performance میاد پایین! اما در واقع چنین چیزی اتفاق نمیفته و کاهش سرعتی نداریم (به شرطی که موارد بالا رعایت بشه)

    مورد دیگه اینکه، اگه قراره این کلاس فقط توش متد باشه و فقط ام یه دونه آبجکت قراره ازش ساخته بشه، چرا اصلا متدها رو static تعریف نکنیم و اصلا آبجکتی ازش نسازیم؟
    جوابش اینه که بله میشه همچین کاری کرد! اتفاقا اینطوری performance هم میره بالاتر و متدها سریع تر کال میشن.

    اما در اینصورت از خیلی چیزای دیگه محروم میشیم. مثلا ارث بری، پیاده سازی interface و abstract و ... که این موارد جز موارد ضروری برای طراحی معماری برنامس و انعطاف پذیری به کدمون میده یعنی میشه بعدا منطق رو عوض کرد و کلی مسائل دیگه...

    مثالی که براش میشه زد مثلا کلاس java.lang.Math که اگر دقت کنید همه متدهاش static هست و هیچ property ای هم در سطح کلاس براش تعریف نشده (به جز چنتا فیلد static final مثل PI که مشکل ساز نیستن)
    الان میشد این کلاسو singleton اش کنن و مثلا همچین چیزی داشتیم :


    Math.getInstance().max(1,2);


    اما واقعا هیچ دلیلی برای singleton تعریف کردن این کلاس وجود نداره، همونطور که اول هم گفتم، بعضی مواقع استفاده کردن از singleton یه چیز اضافس و anti-pattern ه.

  9. #9
    کاربر دائمی آواتار -سیّد-
    تاریخ عضویت
    فروردین 1393
    محل زندگی
    تهران
    پست
    233

    نقل قول: ساختار الگوی Singleton

    ضمن تشکر از توضیحات عالی دوستمون، من هم یک نکته اضافه کنم:

    نقل قول نوشته شده توسط ahmad.mo74 مشاهده تاپیک
    فرض کنیم قراره در هر ثانیه هزاران نفر درخواست بفرستن به سرور و یه رکورد از یه تیبلی رو بخوان. اونوقت شما میای هربار اون کلاسی که وظیفش گرفتن آبجکت از دیتابیسه رو new میکنی و بقیه ماجرا...
    خب اینجا یه فاجعه رخ میده، یعنی؛ به ازای هر درخواست، یبار new کردن یه آبجکت نسبتا سنگین.

    پس بهتره که اون آبجکت singleton باشه.
    در اینجور مواقع که یه شیء سنگین داریم که نمی‌خوایم هی new بشه، بهتره از یه Object-pool استفاده کنیم:
    https://en.wikipedia.org/wiki/Object_pool_pattern
    When it is necessary to work with a large number of objects that are particularly expensive to instantiate and each object is only needed for a short period of time, the performance of an entire application may be adversely affected. An object pool design pattern may be deemed desirable in cases such as these.


    یعنی به خاطر این که تعداد Object هامون می‌خواد زیاد بشه، نباید به سراغ Singleton بریم، بلکه Singleton مال وقتیه که در اثر طراحیمون از یه کلاس فقط و فقط یک شیء مورد نیاز هست.

    در واقع Singleton به خاطر راحتی استفاده ازش، خیلی راحت مورد سوء استفاده قرار می‌گیره و anti-pattern می‌شه.

  10. #10
    کاربر دائمی آواتار ahmad.mo74
    تاریخ عضویت
    مرداد 1393
    محل زندگی
    تهران
    پست
    437

    نقل قول: ساختار الگوی Singleton

    سلام، بله کاملا درسته. اتفاقا میخواستم به این مورد هم اشاره کنم فراموش کردم.

    بهترین مثال هاش همین کانکشن ها به دیتابیسه که در connection pool نگه داری و مدیریت میشن یا مثلا thread pool ها که نمونش تو پکیج java.util.concurrent هست و ...
    آخرین ویرایش به وسیله ahmad.mo74 : جمعه 04 اردیبهشت 1394 در 14:50 عصر

  11. #11

    نقل قول: ساختار الگوی Singleton

    نقل قول نوشته شده توسط -سیّد- مشاهده تاپیک
    در ضمن این کلاس الان thread-safe نیست. اگه بخواد باشه، باید synchronization رعایت بشه:
    [JAVA]
    یا از اون بهتر و با performance بالاتر:

    private static final Object _lock = new Object();
    public static MySingleton getInstance() {

    // do I exist?

    if ( __me == null ) {
    synchronized (_lock) {
    if (__me == null) {

    // if not, instantiate and store

    __me = new MySingleton();
    }
    }

    }

    return __me;

    }

    سلام.چرا نال(خالی بودن) me_دوبارچک میشه؟
    من کتابشو دارم می خونم، که اونجا هم دوبار چک شده، ممنون می شم راهنماییم کنید.

  12. #12
    کاربر دائمی آواتار vahid-p
    تاریخ عضویت
    آذر 1391
    محل زندگی
    تهران
    پست
    1,140

    نقل قول: ساختار الگوی Singleton

    فکر کنم برای این هست که در شرط اول if(__me==null) اگر null نبود که خب این آبجکت وجود داره و سریع return کنه و منتظر بلاک synchronization نمونه.
    اما اگر null بود خب منتظر میمونه _lock آزاد بشه و اونوقت وارد ساخت شی برای __me بشه. اما ممکنه از زمانی که __me نال بوده تا زمانی که _lock آزاد بشه این آبجکت __me ساخته شده باشه و چون singelton هست نباید آبجکت دیگه ای ساخته بشه. خب اگر نبود که میسازیم و بعد هم return میکنیم. همچنین از این نظر خیالمون راحته که داخل synchronization دیگه ممکن نیست پس از چک کردن null بودن __me یک thread دیگه وارد این محدوده بشه.
    میتونست شرط بیرونی رو نذاره ولی همونطور که خودشون هم نوشتن به خاطر performance بالاتر انجام شده چون اگر شرط بیرونی نباشه با اینکه قرار نیست شی جدیدی ساخته باشه ولی اگر کسی قبلا _lock رو اشغال کرده باشه، الکی باید منتظر بمونیم.

    البته این بدبینانه ترین حالت ممکنه رو در نظر گرفته و خود singelton به صورت پیش فرض این مسئله رو در نظر نمیگیرم، مگر اینکه برناممون multithread باشه و به این صورت نباشه که قبل از ساخت چند thread یک بار getInstance کرده باشیم. اگر قبل از ساخت چند thread یکبار از getInstance استفاده کنیم، بقیش حله.

  13. #13
    کاربر دائمی آواتار -سیّد-
    تاریخ عضویت
    فروردین 1393
    محل زندگی
    تهران
    پست
    233

    نقل قول: ساختار الگوی Singleton

    نقل قول نوشته شده توسط vahid-p مشاهده تاپیک
    فکر کنم برای این هست که در شرط اول if(__me==null) اگر null نبود که خب این آبجکت وجود داره و سریع return کنه و منتظر بلاک synchronization نمونه.
    اما اگر null بود خب منتظر میمونه _lock آزاد بشه و اونوقت وارد ساخت شی برای __me بشه. اما ممکنه از زمانی که __me نال بوده تا زمانی که _lock آزاد بشه این آبجکت __me ساخته شده باشه و چون singelton هست نباید آبجکت دیگه ای ساخته بشه. خب اگر نبود که میسازیم و بعد هم return میکنیم. همچنین از این نظر خیالمون راحته که داخل synchronization دیگه ممکن نیست پس از چک کردن null بودن __me یک thread دیگه وارد این محدوده بشه.
    میتونست شرط بیرونی رو نذاره ولی همونطور که خودشون هم نوشتن به خاطر performance بالاتر انجام شده چون اگر شرط بیرونی نباشه با اینکه قرار نیست شی جدیدی ساخته باشه ولی اگر کسی قبلا _lock رو اشغال کرده باشه، الکی باید منتظر بمونیم.
    دقیقاً همینطوره که فرمودید. یعنی به خاطر اون اول ماجرا که هنوز شیء ساخته نشده، کلاً برای ابد درگیر یه lock-unlock الکی نشیم!

    اسم این روش هست double-checked locking و یه روش شناخته شده هست. ولی با کمال تأسف و تأثر، باید به عرض برسونم، که این روش ممکنه درست کار نکنه:
    The "Double-Checked Locking is Broken" Declaration

    من به شخصه خیلی ناراحت شدم وقتی فهمیدم این روش ممکنه کار نکنه! :(
    اما روش‌های جایگزین برای مشکلاتی که گفته وجود داره، برای اطلاعات بیشتر به ویکیپدیای این موضوع مراجعه کنید. نمونه کدی که اونجا اورده رو اینجا هم میارم:

    // Correct lazy initialization in Java
    class Foo {
    private static class HelperHolder {
    public static final Helper helper = new Helper();
    }

    public static Helper getHelper() {
    return HelperHolder.helper;
    }
    }

  14. #14
    کاربر دائمی آواتار vahid-p
    تاریخ عضویت
    آذر 1391
    محل زندگی
    تهران
    پست
    1,140

    نقل قول: ساختار الگوی Singleton

    اسم این روش هست double-checked locking و یه روش شناخته شده هست. ولی با کمال تأسف و تأثر، باید به عرض برسونم، که این روش ممکنه درست کار نکنه:
    The "Double-Checked Locking is Broken" Declaration

    من به شخصه خیلی ناراحت شدم وقتی فهمیدم این روش ممکنه کار نکنه! :(
    جالب بود و ممنون که مطلب رو تکمیل کردید.

    نمیشه داخل synchronization و بعد از ساخت آبجکت یک متد از اون آبجکت رو صدا بزنیم تا مشکل Lazy initialization برطرف بشه؟!
    مثلا
    if ( __me == null ) {
    synchronized (_lock) {
    if (__me == null) {

    // if not, instantiate and store

    __me = new MySingleton();
    __me.noOperation();
    }
    }

    }

  15. #15
    کاربر دائمی آواتار -سیّد-
    تاریخ عضویت
    فروردین 1393
    محل زندگی
    تهران
    پست
    233

    نقل قول: ساختار الگوی Singleton

    نقل قول نوشته شده توسط vahid-p مشاهده تاپیک
    جالب بود و ممنون که مطلب رو تکمیل کردید.

    نمیشه داخل synchronization و بعد از ساخت آبجکت یک متد از اون آبجکت رو صدا بزنیم تا مشکل Lazy initialization برطرف بشه؟!
    مثلا
    if ( __me == null ) {
    synchronized (_lock) {
    if (__me == null) {

    // if not, instantiate and store

    __me = new MySingleton();
    __me.noOperation();
    }
    }

    }
    نمی‌دونم این کار مشکل رو برطرف می‌کنه یا نه. چون کامپایلر که هیچ، JIT هم توی جاوا فعال هست و انقدر هوشمند هست که ممکنه کل اون فراخوانی رو حذف کنه! البته می‌تونیم توش یه عملیاتی بذاریم که از دید سیستم nop نباشه، ولی واقعاً nop باشه! مثلاً با مقایسهٔ زمان فعلی سیستم با یه عددی که مطمئن هستیم مال سالها پیش هست، یه چیزی رو توی خروجی چاپ کنیم:

    if (System.currentTimeMillis() < 1000000000) {
    System.out.println("OMG! This system's time is too old! ;)");
    }

    ولی باز مطمئن نیستم که مشکل اینطوری حل می‌شه یا نه! یه جملهٔ جالبی توی اون مقاله داره:

    It doesn't work

    There are lots of reasons it doesn't work. The first couple of reasons we'll describe are more obvious. After understanding those, you may be tempted to try to devise a way to "fix" the double-checked locking idiom. Your fixes will not work: there are more subtle reasons why your fix won't work. Understand those reasons, come up with a better fix, and it still won't work, because there are even more subtle reasons.

    Lots of very smart people have spent lots of time looking at this. There is no way to make it work without requiring each thread that accesses the helper object to perform synchronization.

    البته این معنی‌اش این نیست که آدم مغزش رو تعطیل کنه و هر ایده‌ای به ذهنش رسید بگه حتماً غلطه! ولی می‌شه این برداشت رو کرد که به این راحتی نمی‌شه حلش کرد!

  16. #16
    کاربر دائمی آواتار vahid-p
    تاریخ عضویت
    آذر 1391
    محل زندگی
    تهران
    پست
    1,140

    نقل قول: ساختار الگوی Singleton

    این خیلی بده یه چیزی که منطقا میخواهیم انجام بشه، به دلایلی انجام نشه یا به تاخیر بیفته.
    میشه این موضوع رو شبیه سازی کنیم و در اجراهای بسیار زیادی، ببینیم آیا با این ترفندهایی که گفتیم باز هم ممکنه دو بار new آبجکت بشه.

    بازم ممنون به خاطر نکاتی که به اشتراک گذاشتید

  17. #17
    کاربر دائمی آواتار -سیّد-
    تاریخ عضویت
    فروردین 1393
    محل زندگی
    تهران
    پست
    233

    نقل قول: ساختار الگوی Singleton

    توجه کنید که با تمام این بحث‌ها، به علت وجود cache در CPU، باید متغیر me__ رو به صورت volatile تعریف کنیم. این هم خودش به نوبهٔ خودش خیلی بده! چون متغیری که volatile باشه، رسماً cache رو پردازنده نابود می‌کنه و به ازای هر دسترسی به اون، یه دسترسی به حافظه (RAM) هم انجام می‌شه که به شدت کارآمدی رو پایین میاره. یعنی هر بار شما این تابع getInstance رو فراخوانی می‌کنید، باید معطل دسترسی به حافظه بشید (سرعت دسترسی به cache پردازنده قابل مقایسه با سرعت دسترسی به حافظه نیست). البته اینجا صحبت از نانوثانیه هست! یعنی این «به شدت کارآمدی رو پایین میاره» در حد چند نانوثانیه هست! خیلی نگران نباشید! :)
    در ضمن استفاده از volatile امکان انجام برخی از انواع optimization های زمان compile رو هم از سیستم می‌گیره (مثلاً دیگه به راحتی نمی‌شه فراخوانی این تابع getInstance رو inline کرد).

    منم یه راهکار دارم که تا به حال امتحانش نکردم: می‌شه با زمان مسئله رو حل کرد، یعنی مثلاً اگه آدم مطمئنه که حداکثر بعد از مثلاً یک ساعت از اجرای برنامه، حتماً این متغیر initialize شده، می‌شه بعد از یک ساعت دیگه از این متغیر volatile استفاده نکرد. البته این ایده‌ام خیلی اولیه هست و ممکنه توی اجراش به مشکل بخوریم!

تاپیک های مشابه

  1. معایب الگوی طراحی Singleton
    نوشته شده توسط keyhan.taktaz در بخش Android Studio
    پاسخ: 0
    آخرین پست: پنج شنبه 06 شهریور 1393, 13:40 عصر
  2. شبیه سازی ساختار نمایش درختی فهرست یک کتاب
    نوشته شده توسط Ali_Mor در بخش VB.NET
    پاسخ: 4
    آخرین پست: شنبه 04 مرداد 1382, 23:19 عصر

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •