10

ارث‌بری و Interface؛ خانواده‌سازی بدون دعوای ارث

کدها هم گاهی پدر و فرزند دارن؛ فقط باید اصولی باشه که آخرش دادگاه نره.

درس 10 از 20

کلاس‌ها پیش‌فرض final هستن

در کاتلین کلاس‌ها به‌صورت پیش‌فرض قابل ارث‌بری نیستن. برای ارث‌بری باید `open` بنویسی. این کار جلوی طراحی شلخته رو می‌گیره؛ هرکی از راه رسید از کلاست بچه نسازه.

مثال را با چند مقدار دیگر هم امتحان کن؛ چون برنامه‌نویسی با نگاه کردن یاد گرفته نمی‌شود، با خراب کردن و درست کردن جا می‌افتد.

open و override
open class Animal(val name: String) {
    open fun sound() = "..."
}

class Cat(name: String) : Animal(name) {
    override fun sound() = "Meow"
}

fun main() {
    val cat = Cat("پشمک")
    println(cat.sound())
}
خروجی یا نتیجه اجرا
Meow
نکته کاربردی: این بخش اسکلت ذهنی درس را می‌سازد. وقتی بدانی این قطعه دقیقاً چه مسئله‌ای را حل می‌کند، بعداً موقع پروژه فقط syntax حفظی تحویل نمی‌دهی؛ تصمیم درست می‌گیری. اگر خروجی با چیزی که انتظار داشتی فرق کرد، اول مقدار متغیرها و مسیر اجرا را چک کن؛ ۹۰٪ باگ‌های اول راه همین‌جا قایم شده‌اند.

Interface یعنی قرارداد

interface می‌گه هرکلاسی که منو قبول کرد، باید این رفتارها رو داشته باشه. مثل قرارداد کار؛ امضا کردی، دیگه باید انجام بدی.

مثال را با چند مقدار دیگر هم امتحان کن؛ چون برنامه‌نویسی با نگاه کردن یاد گرفته نمی‌شود، با خراب کردن و درست کردن جا می‌افتد.

interface
interface Clickable {
    fun click()
}

class Button : Clickable {
    override fun click() {
        println("کلیک شد!")
    }
}
خروجی یا نتیجه اجرا
خروجی مستقیم ندارد؛ کلاس Button قرارداد Clickable را اجرا کرده و آماده صدا زدن click() است.
نکته کاربردی: اینجا باید به رفتار کد نگاه کنی، نه فقط ظاهرش. مقدارها را عوض کن و دوباره اجرا بگیر تا دستت بفهمد برنامه چطور واکنش نشان می‌دهد. اگر خروجی با چیزی که انتظار داشتی فرق کرد، اول مقدار متغیرها و مسیر اجرا را چک کن؛ ۹۰٪ باگ‌های اول راه همین‌جا قایم شده‌اند.

Polymorphism

می‌تونی چند نوع مختلف رو با یک نوع مشترک کنترل کنی. این باعث می‌شه کد انعطاف‌پذیرتر بشه و با هر تغییر کوچیک، کل پروژه مثل دومینو نریزه.

مثال را با چند مقدار دیگر هم امتحان کن؛ چون برنامه‌نویسی با نگاه کردن یاد گرفته نمی‌شود، با خراب کردن و درست کردن جا می‌افتد.

چندریختی
fun makeItClick(view: Clickable) {
    view.click()
}

fun main() {
    makeItClick(Button())
}
خروجی یا نتیجه اجرا
کلیک شد!
نکته کاربردی: این الگو در پروژه واقعی زیاد تکرار می‌شود. از همین حالا تمیز و خوانا بنویس تا بعداً موقع دیباگ، خودت به خودت فحش ندهی. اگر خروجی با چیزی که انتظار داشتی فرق کرد، اول مقدار متغیرها و مسیر اجرا را چک کن؛ ۹۰٪ باگ‌های اول راه همین‌جا قایم شده‌اند.

نتیجه این درس 🎯

ارث‌بری و interface وقتی خوب‌اند که رابطه واقعی وجود داشته باشد. اگر فقط برای کلاس‌بازی استفاده‌شان کنی، پروژه بعداً تبدیل به شجره‌نامه قاجاری می‌شود.

تمرین! 🧠

یک interface به نام Payable بساز و کلاس Invoice را مجبور کن تابع pay را پیاده‌سازی کند.

جواب تمرین
interface Payable {
    fun pay()
}

class Invoice(private val amount: Int) : Payable {
    override fun pay() {
        println("پرداخت $amount تومان انجام شد")
    }
}

fun main() {
    val invoice = Invoice(250000)
    invoice.pay()
}
خروجی جواب
پرداخت 250000 تومان انجام شد