Menu
Coddy logo textTech

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בחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: Kotlin אונליין