Delegation in Kotlin

یکی از ویژگی‌های مهم کاتلین پیاده سازی آسان Delegation هست، منتها قبل از اون باید ببینیم اصلا Delegation چی هست !لغت Delegation در انگلیسی به معنی "نمایندگی" هست و Delegate یعنی نماینده یا نمایندگی/وکالت دادن، الگوی Delegation در زبان‌های برنامه نویسی به صورت کلی به این صورت هست که یک سری وظایف رو در کلاس A به کلاس نماینده ای به اسم B بذاریم، به نظرم این به نوعی به قاعده اول اصول SOLID یعنی Single Responsibility هم می‌تونه ربط پیدا کنه (چرا؟) و مانع تولید یک God class بزرگ بشه .ما برای اینکار می‌تونیم از Delegation هم استفاده نکنیم و به جاش از وراثت استفاده کنیم، یعنی یک سری وظایف base تر رو به کلاس والد ببریم، منتها باید بدونیم که چه زمانی از کدوم یک از این مفاهیم استفاده کنیم، زمانی که این وظیفه امکان داره بعدا در کلاس‌های دیگه تکرار بشه یا به هر دلیلی نمی‌خوایم اون وظیفه در کلاس های دیگه (فرزند) override بشن یا کلاس والد final باشه بهتره از Delegation استفاده کنیم، برای استفاده از وراثت بهتره فقط زمانی اینکار صورت بگیره که واقعا یک رابطه "کلاس A یک نوع از کلاس B هست" وجود داشته باشه (تو رفرنس های انگلیسی این رو is-a میگن) .مثلا فرض کنید یک کلاس Shape داریم که قراره یک سری کارا توش انجام بشه و در کنار اون کارا مساحت اون Shape هم حساب بشه، اینجا می‌تونیم یک کلاس AreaCalculator ایجاد کنیم که وظیفه محاسبه مساحت رو داره و یک Instance از این کلاس در Shape داشته باشیم که این کار رو انجام بده، به همین راحتی ! به این مفهوم میگن Delegation .یک نکته دیگه هم که ما مفهومی به اسم Composition هم داریم که در لغت به معنی "ترکیب" هست، این مفهوم در واقع جمله "کلاس A یک کلاس B را دارد" هست که در رفرنس های انگلیسی به اون "has-a" میگن، به نظر می‌رسه که Delegation مفهوم یکسانی با Composition داشته باشه ، نه ؟ در واقع Composition به رابطه بین اشیا با هم می‌پردازه در حالی که Delegation به سپردن کار اشیا به هم می‌پردازه و یکی از کاربردهای Composition ایجاد یک Delegation هست، مثلا فرض کنید یک کلاس به اسم House داریم که با استفاده از CompostionComposition یک کلاس به اسم Room رو داخل خودش داره، آیا اینجا Delegation داریم؟ نه ! Room چه وظیفه ای از House رو می‌خواد انجام بده ؟ اما فرض کنید داخل همین کلاس House یک کلاس AlarmManager داریم که وظیفه دادن هشدار خطر به پلیس رو در شرایط خاصی داره، اینجا ما Delegation داریم چون یک وظیفه که بر عهده House بوده رو به کلاس AlaramManager دادیم که در واقع این AlaramManager خودش با House یک رابطه Composition هم داره !خب حالا یک مثال ساده از قضیه ببینیم که در کاتلین چطوری باید Delegation رو پیاده کنیم :صورت مساله : یک کلاس مستطیل داریم که می‌خوایم مساحتش رو حساب کنیم، خیلی ساده !راه حل با استفاده از ارث بری :این راه حل برای این مساله مورد قبول ما نیست چون ماهیت محاسبه مساحت به کلاس نباید ربطی داشته باشه و ما می‌تونیم به راحتی از Delegation استفاده کنیم !راه حل مقدماتی با Delegation : در اینجا یک Interface به اسم AreaCalculator داریم که در Shape به صورت Delegation استفاده شده، این راه حل به نظر راه حل مناسبی میاد، اما برای جاوا !!!! در کاتلین به صورت فوق العاده راحت تری این کار رو میشه کرد .راه حل کامل :خب به این کد نگاه کنیم، یک interface به اسم AreaCalculator داریم که Shape باهاش implement شده، اما از اونجایی که Shape خودش abstract هست پس نیازی نیست متد area رو override کنه، فعلا از by صرف نظر می‌کنیم، حالا در کلاس Rectangle ما حتما باید area رو پیاده سازی کنیم چون این کلاس از Shape ارث برده و ما هم area رو اونجا پیاده سازی نکردیم، ولی اگه ببینید ما حتی در Rectangle هم اینکار رو نکردیم !!! پس area از کجا داره میاد ؟ اینجا اپراتور by به کمک ما میاد ، فرمول کلی قضیه by به این صورته :ما در هنگامی که از کلاس Bahman یک شی می‌سازیم Folan_Imp مورد نظرمون رو که از جنس Folan هست (از اون Implement شده) بهش می‌دیم و حالا با استفاده از by دیگه نیازی نیست خودمون دستی متد های Folan رو پیاده کنیم، بلکه کلاس Bahman میاد متدهای مورد نظر رو از Folan_Imp میگیره !!!!حالا شما می‌تونی یک جا به Bahman یک Folan_Imp بدی و یک جای دیگه Folan_Imp_2 رو بدی !!! بسته به نیازی که در اون موقع داری !در مثال مستطیل هم تابع area در واقع از AreaCalculator_Rectangle داره گرفته میشه !نکته : ما همچنان می‌تونیم خودمون area رو در Rectangle به صورت override پیاده سازی کنیم و مشکلی هم نداره، اما وقتی این کار رو بکنیم چی میشه ؟ وقتی area رو صدا بزنیم میاد از متد override شده در داخل Rectangle استفاده می‌کنه یا از داخل AreaCalculator_Rectangle ؟ جواب اینکه میاد اونی که داخل Rectangle هست رو استفاده می‌کنه، مثالی که بالا زدم بسیار ساده بود ، در خیلی از مواقع مسلما interface ما متدهای بیشتری داره و شاید ما نیاز داشته باشیم بعضی از متدهاش رو تغییر بدیم و می‌تونیم اونایی که نیازه رو داخل خود کلاسی که داره عمیلات Delegation رو به عهده یه کلاس دیگه می‌ذاره override کنیم !پیشنهاد می‌کنیم سورس این مطلب رو از خود سایت کاتلین هم بخونید، اونجا مثال ساده تری زده ولی در مورد مفهوم Delegation توضیح خاصی نداده و یک رفرنس به ویکیپدیا داده .آدرس کانال تلگرامی ما : لینکمن رو در لینکدین ، اینستاگرام و یوتیوب دنبال کنید !!!