Extension Functions در Kotlin : توابع اکستنشن


قراره توی این مطلب به یکی از ویژگیهای خفن و پرکاربرد کاتلین به اسم Extension Functions بپردازیم.
این ویژگی بهت اجازه میده که بدون دست زدن به کد اصلی کلاسها یا ارثبری از اونها، یه سری قابلیت جدید بهشون اضافه کنی. توی دنیای برنامهنویسی اندروید که کلی کد تکراری و کارهای روتین داریم، این ویژگی مثل آب روی آتیش میمونه. پس اگه دوست داری کدت خواناتر و تمیزتر بشه، این مطلب برات طلاست.
Extension Function چیه؟
خیلی ساده بخوام بگم، Extension Function یعنی اینکه به یه کلاس، یه متد (تابع) اضافه کنی، بدون اینکه کد اصلی اون کلاس رو تغییر بدی. این یعنی تو میتونی رفتار کلاسهایی مثل View، Activity یا حتی String رو گسترش بدی و راحتتر ازشون استفاده کنی.
مثال: فرض کن میخوای یه متد به کلاس String اضافه کنی که فقط حرف اول یه رشته رو بزرگ کنه. با استفاده از Extension Function این کار خیلی آسونه:
fun String.capitalizeFirst(): String { return this.replaceFirstChar { it.uppercase() } }
توضیحات:
- this
به رشتهای اشاره داره که این تابع روی اون صدا زده شده. به عبارت دیگه، هر رشتهای که از این متد استفاده کنه، به عنوان ورودی تابع در نظر گرفته میشه. - replaceFirstChar()
این یه تابع داخلی (Built-in) در کاتلین هست که به شما اجازه میده اولین کاراکتر رشته رو تغییر بدید. در اینجا، از این تابع برای تغییر دادن اولین حرف استفاده شده.
- { it.uppercase() }
it
به اولین کاراکتر رشتهای کهreplaceFirstChar
روی اون اعمال شده اشاره داره.
uppercase()
این کاراکتر رو به حرف بزرگ (Uppercase) تبدیل میکنه. به عبارت دیگه، این قسمت مسئول اینه که اولین حرف رشته، بزرگ بشه.
حالا میتونی خیلی راحت از این متد توی برنامهات استفاده کنی:
val name = "kotlin" println(name.capitalizeFirst()) // خروجی: Kotlin
ساختار کلی Extension Function
ساختار کلی یه Extension Function به این شکله:
fun ClassName.functionName(parameters): ReturnType { // بدنهی تابع }
- ClassName: کلاسی که میخوای گسترشش بدی.
- functionName: اسم تابعی که اضافه میکنی.
- parameters: ورودیهای دلخواه تابع (اگه نیاز باشه).
- ReturnType: نوع خروجی تابع.
ویژگیهای مهم Extension Functions
- نیازی به ارثبری نداری: لازم نیست یه کلاس رو Subclass کنی تا یه متد جدید بهش اضافه کنی.
- دست نخورده موندن کد اصلی: نیازی نیست به سورس کد کلاس دسترسی داشته باشی.
- کد تمیز و قابل استفاده مجدد: میتونی قابلیتهای مشترک رو به صورت Extension Function بنویسی و توی کل پروژه استفاده کنی.
- احترام به Scope: این توابع فقط توی محدودهای که تعریف شدن کار میکنن.
Extension Functions چطور کار میکنن؟
وقتی یه Extension Function رو فراخوانی میکنی، کاتلین اینجوری رفتار میکنه که انگار این متد از اول عضو کلاس بوده. اما در واقعیت، این توابع پشت صحنه به صورت متدهای استاتیک کار میکنن و هیچ هزینهای از نظر عملکرد (Performance) ندارن.
نکتههای مهم:
- کلاس اصلی تغییر نمیکنه: این توابع فقط روی نمونههای کلاس موقع اجرا (Runtime) کار میکنن.
- اولویت با توابع خود کلاس: اگه کلاس اصلی تابعی با همون اسم داشته باشه، تابع کلاس اصلی اجرا میشه.
- چرا از Extension Function توی اندروید استفاده کنیم؟
- کارهای روتین رو ساده کن: مثلا نمایش Toast یا مدیریت دید (View) رو راحتتر کن.
- کد خواناتر بشه: از شر کدهای تکراری و اضافه خلاص شو.
- نیازی به کلاسهای Utility نیست: به جای ساختن کلاسهای Utility، میتونی از Extension Functions استفاده کنی.
- کلاسهای فریمورک رو ارتقا بده: میتونی کلاسهای مثل Activity، Fragment یا View رو تقویت کنی.
Modifier ها در کامپوز چطوری کار میکنند ؟مدیفایر Modifier ها در جت پک کامپوز : 3 دسته اصلی
مثالهای کاربردی از Extension Functions
افزودن متد به View
فرض کن میخوای یه متد برای Visible و Gone کردن ویوها داشته باشی:
fun View.show() { this.visibility = View.VISIBLE } fun View.hide() { this.visibility = View.GONE }
استفاده:
button.show() // نمایش دکمه textView.hide() // مخفی کردن TextView
افزودن متد به Activity
یه راه راحت برای شروع یه اکتیویتی جدید اضافه کن:
inline fun <reified T : Activity> Context.startActivity() { val intent = Intent(this, T::class.java) startActivity(intent) }
استفاده:
startActivity<MainActivity>() // شروع MainActivity
افزودن متد به String
مثلا برای بررسی فرمت ایمیل:
fun String.isValidEmail(): Boolean { return android.util.Patterns.EMAIL_ADDRESS.matcher(this).matches() }
استفاده:
val email = "[email protected]" if (email.isValidEmail()) { println("ایمیل معتبره") } else { println("ایمیل نامعتبره") }
افزودن متد به Fragment
مثلا برای نمایش Toast توی Fragment:
fun Fragment.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) { Toast.makeText(requireContext(), message, duration).show() }
استفاده:
showToast("پیغام از Fragment")
افزودن Divider به RecyclerView
یه خط جداکننده به RecyclerView اضافه کن:
fun RecyclerView.addDivider(@DrawableRes drawableRes: Int) { val divider = DividerItemDecoration(this.context, DividerItemDecoration.VERTICAL) ContextCompat.getDrawable(this.context, drawableRes)?.let { divider.setDrawable(it) } addItemDecoration(divider) }
استفاده:
recyclerView.addDivider(R.drawable.divider_drawable)
سناریوهای واقعی استفاده از Extension Functions
- کمک به رابط کاربری (UI Helpers): مثلا تغییر Visibility یا آپدیت کردن ویوها.
- اعتبارسنجی (Validation): مثل بررسی فرمت ایمیل یا شماره تلفن.
- ناوبری (Navigation): ساخت متدهای کمکی برای شروع اکتیویتیها یا فرگمنتها.
- مدیریت دادهها: اضافه کردن متدهایی به String یا List برای انجام عملیاتهای رایج.
مزایای Extension Functions
- کد خواناتر و سادهتر: منطق کد رو مستقیما توی کلاسها جاسازی میکنی.
- استفاده مجدد از کد: یه تابع بنویس و توی کل پروژه ازش استفاده کن.
- نیازی به ارثبری نیست: بدون ساختن کلاس فرزند، قابلیت اضافه کن.
محدودیتهای Extension Functions
- عدم دسترسی به اعضای خصوصی: این توابع نمیتونن به متغیرها یا متدهای private یا protected دسترسی داشته باشن.
- تغییر واقعی کلاس نیست: این توابع صرفا یه ظاهر خوشگل برای کدنویسی هستن و کلاس اصلی تغییر نمیکنه.
- ابهام با ارثبری: اگه یه کلاس فرزند متدی با همون نام داشته باشه، متد کلاس فرزند اجرا میشه.
Extension Functions یکی از ویژگیهای جذاب کاتلین هستن که میتونن بهرهوری و خوانایی کد رو توی برنامهنویسی اندروید به شدت افزایش بدن. با استفاده از این توابع، میتونی کارهای تکراری رو سادهتر کنی، کد تمیزتری بنویسی، و قابلیتهای جدیدی به کلاسهای موجود اضافه کنی، بدون اینکه اونها رو تغییر بدی یا ازشون ارثبری کنی.
حالا وقتشه که این ابزار قدرتمند رو توی پروژههات استفاده کنی و ازش لذت ببری! 😎