دانستنی‌ها

متدهای پیش‌فرض در جاوا 8

متدهای پیش‌فرض در واسط‌ها، برای اولین بار در جاوا 8 معرفی شد. در این مقاله توضیح می‌دهیم که متدهای پیش‌فرض چه هستند و چه تغییری در طراحی API جاوا ایجاد کرده‌اند.

یک طراحی عادی

قبلا، واسط‌ها در جاوا تنها می‌توانستند متدهای بدون بدنه و بدون پیاده‌سازی داشته باشند و در واقع فقط امضای (signature) متدها در واسط نوشته می‌شد.

برای اینکه بتوان به این طراحی، پیاده‌سازی اضافه کرد، حتما نیاز به یک کلاس (abstract یا غیر abstract) بود. به این ترتیب، طراحی API قدیمی، دارای چنین سلسه‌مراتبی بود:

  1. در ریشه، واسط قرارداد و امضای متد را تعریف می‌کند.
  2. کلاس میانی، رفتار مشترک را پیاده‌سازی می‌کند.
  3. اگر نیازی بود، یک کلاس در این سلسه‌مراتب، این رفتار را بازنویسی (override) می‌کند.

مساله

تا زمانی که کلاس‌های خارج از دسترسِ طراح API بتواند واسط را پیاده‌سازی کند، این طراحی بی‌نقص است. سلسه‌مراتب زیر، بخش List از Collections API جاوا به همراه کلاس سفارشیِ MyList را نشان می‌دهد.

بیایید متد ()sort را در واسط List تعریف کنید. تنها کلاس‌های AbstractList و MyList واقعا باید این متد را پیاده‌سازی کنند.

واضح است که احتمال دارد یک پیاده‌سازی کاملا یکسان برای متد ()sort را در هر دو کلاس قرار دهیم (کاملا منطقی هم هست). به این ترتیب، پیاده‌سازی‌های مستقیمِ واسط List، مجبورند متد ()sort از AbstractList را تکرار (duplicate) کنند.

به منظور جلوگیری از تکرار کد، طراحان API جاوا مجبور شدند متد ()sort را از واسط List به یک کلاس نامرتبط (Collections) که تنها دارای متدهای static است، منتقل کنند.

با این کار، مشکل کدهای مشترک حل می‎شود و حالا دیگر تنها یک متد واحد مسئولیت مرتب‎سازی را برعهده دارد.

در مقابل، متدهای static، شی‎گرا نیستند و بدتر از آن، هیچ رابطه‎ای از List به Collections در کد وجود ندارد (البته یک رابطه در جهت عکس وجود دارد). به این ترتیب، اگر کسی از وجود کلاس Collections و ویژگی‎هایش مطلع نباشد، هیچ راهی وجود ندارد که مطلع شود.

راه حل: متدهای پیش‎فرض

حالا تصور کنید که پیاده‎سازی کد در واسط امکان‎پذیر بود. در این صورت، متد ()sort می‎توانست در واسط List پیاده‎سازی شود و نمودار کلاس‌هایمان شبیه شکل زیر می‎شد:

به این ترتیب، مشکل بالا حل می‎شد. به صورت پیش‎فرض، هر پیاده‎سازی لیست، از طریق وراثت به متد ()sort دسترسی خواهد داشت.

دقیقا همین موضوع، دلیل وجود متدهای پیش‎فرض است. نه کمتر و نه بیشتر.

جهت رفع کنجکاوی: پیاده‎سازی ()Collections.sort به صورت زیر بازنویسی شده است تا وظیفه مرتب‎سازی به متد پیش‎فرض محول شود:

// Without generics for better readability
public class Collections {
    public static void sort(List list) {
        list.sort(null);
    }
}

جمع‎بندی

اگر کارتان به جایی رسید که مجبور شدید به جای اینکه یک تکه‎کد را در یک واسط مشترک قرار دهید، آن را در کلاس‎های مختلف تکرار کنید، در این صورت، استفاده از متدهای پیش‎فرض به جای استفاده از کلاس‎های کمکی، با اختلاف، راه حل هوشمندانه‎تری خواهد بود.

منبع

نوشته های مشابه

یک دیدگاه

  1. ‎‌‍مقاله مفید و جالبی بود. برام سوال پیش اومده بود که با وجود امکان متد پیش‌فرض در واسط‌ها، چه نیازی به کلاس‌های کمکی داریم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا