Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

super والمنشئات

جزء من قسم البرمجة كائنية التوجه في رحلة Kotlin على Coddy. الدرس 19 من 57.

يستدعي super.method() إصدار الصنف الأب من الطريقة من داخل التجاوز. يمكن للصنف الفرعي توسيع السلوك الموروث بدلًا من استبداله:

open class Notification(val text: String) {
    open fun render() = "[info] $text"
}
class Reminder(text: String, val minutes: Int) : Notification(text) {
    override fun render() = super.render() + " (in $minutes min)"
}

داخل main:

println(Notification("backup done").render())
println(Reminder("meeting", 10).render())

الناتج:

[info] backup done
[info] meeting (in 10 min)

يجب على كل فئة فرعية استدعاء مُنشئ الفئة الفائقة. باستخدام مُنشئ أساسي، يكون الاستدعاء جزءًا من الترويسة، : Base(arguments)، ويمكن حساب الوسيطات من معاملات الفئة الفرعية:

open class Product(val name: String, val price: Int)

class Discounted(name: String, price: Int, val percent: Int) :
    Product(name, price * (100 - percent) / 100)

داخل main:

val tea = Discounted("tea", 500, 10)
println("${tea.name} ${tea.price} (${tea.percent}% off)")

الناتج:

tea 450 (10% off)

يتم الإنشاء من أعلى التسلسل الهرمي إلى أسفله: تُنفَّذ مُهيِّئات الخصائص وكتل init الخاصة بالفئة الفائقة أولًا، ثم الخاصة بالفئة الفرعية:

open class Base(name: String) {
    init { println("Base init for $name") }
}
class Child(name: String) : Base(name.uppercase()) {
    init { println("Child init for $name") }
}

داخل main:

Child("kit")

المخرجات:

Base init for KIT
Child init for kit

يستدعي الصنف الذي لا يحتوي على مُنشئ أساسي الصنفَ الفائق من كل مُنشئ ثانوي باستخدام super(...)، أو يفوّض إلى مُنشئ آخر من مُنشئاته باستخدام this(...):

open class Shape(val name: String)

class Rect : Shape {
    val w: Int
    val h: Int

    constructor(w: Int, h: Int) : super("rect") {
        this.w = w
        this.h = h
    }

    constructor(side: Int) : this(side, side)
}

داخل main:

val r = Rect(3)
println("${r.name} ${r.w}x${r.h}")

الناتج:

rect 3x3

نظرًا إلى أن الصنف الفائق تتم تهيئته أولًا، فلا ينبغي له استدعاء الأعضاء open من مُنشئه أو من init. يُنفَّذ التجاوز قبل أن تحصل خصائص الصنف الفرعي نفسه على قيمها:

open class Base {
    init { println("Base sees: ${describe()}") }
    open fun describe() = "base"
}
class Child : Base() {
    val label = "child"
    override fun describe() = "label is $label"
}

داخل main:

Child()

الناتج:

Base sees: label is null
challenge icon

التحدي

سهل

تحتوي Notification(text) على طريقة مفتوحة render() تُرجع [info] text. أكمل الفئات الفرعية: تُرجع render() الخاصة بـ Warning القيمة [warn] TEXT مع كتابة النص بأحرف كبيرة، بينما تُرجع Reminder، التي تخزّن أيضًا minutes، نتيجة الفئة الفائقة متبوعةً بـ (in 10 min)، باستخدام super.

يقرأ الكود المُقدَّم أسطرًا بتنسيق info,text أو warn,text أو remind,text,10، وينشئ الكائن المطابق في List<Notification> واحدة، ويطبع render() لكل كائن.

يجب أن تضع كودك في Notification.kt وWarning.kt وReminder.kt. يحتوي Main.kt على كود الإدخال/الإخراج المُقدَّم، ولا يمكن تعديله.

جرّب بنفسك

fun main() {
    // كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
    val input = generateSequence(::readLine).toList()
    val notes = mutableListOf<Notification>()
    for (line in input) {
        val p = line.split(",")
        notes.add(when (p[0]) {
            "warn" -> Warning(p[1])
            "remind" -> Reminder(p[1], p[2].toInt())
            else -> Notification(p[1])
        })
    }
    for (n in notes) println(n.render())
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: Playground لـ Kotlin