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التحدي
سهلتحتوي 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())
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتالمنشئات الأساسيةكتل init والتحقق من الصحةالمنشئات الثانويةمراجعة - بطاقة المكتبة4الوراثة
الأصناف المفتوحة والأصناف الفرعيةتجاوز الأعضاءsuper والمنشئاتالأصناف المجرّدةمراجعة - دليل الموظفينتدرّب بنفسك: Playground لـ Kotlin