الأصناف المفتوحة والأصناف الفرعية
جزء من قسم البرمجة كائنية التوجه في رحلة Kotlin على Coddy. الدرس 17 من 57.
يتيح الوراثة لصنف أن يبني على صنف آخر. يحصل الصنف الفرعي على كل خاصية وطريقة في الصنف الفائق، ويمكنه إضافة خصائصه وطرقه الخاصة. تكون أصناف Kotlin مغلقة افتراضيًا، لذا يجب وضع العلامة open على الصنف قبل أن يتمكن صنف آخر من التوسّع فيه:
open class Animal(val name: String) {
fun describe() = "$name is an animal"
}
class Dog(name: String) : Animal(name) {
fun fetch() = "$name fetches the ball"
}داخل main:
val rex = Dog("Rex")
println(rex.describe())
println(rex.fetch())الناتج:
Rex is an animal
Rex fetches the ballclass Dog(name: String) : Animal(name) تعني أن Dog ترث من Animal وتمرر name إلى مُنشئ الصنف الفائق. لا تحتوي المعلمة على val، لأن الخاصية موجودة بالفعل في Animal. لا يمكن توسيع صنف ليس open:
class Plant(val name: String)
// class Tree(name: String) : Plant(name) // خطأ: هذا النوع final، لذا لا يمكن الوراثة منه
open class Vehicle(val wheels: Int)
class Bike : Vehicle(2) // يمرّر قيمة ثابتة
class Truck(val load: Int) : Vehicle(6) // يضيف خاصية خاصة بهالـ Dog هو Animal، لذا يمكن استخدام نسخة من فئة فرعية حيثما يُتوقَّع نوع الفئة الفائقة. يمكن لقائمة واحدة من النوع List<Animal> أن تحتوي على كلاب وقطط وحيوانات عادية، ولكل عنصر أعضاء Animal:
open class Animal(val name: String) {
fun describe() = "$name is an animal"
}
class Dog(name: String) : Animal(name)
class Cat(name: String, val indoor: Boolean) : Animal(name)داخل main:
val pets: List<Animal> = listOf(Dog("Rex"), Cat("Tom", true), Animal("Generic"))
for (p in pets) println(p.describe())الناتج:
Rex is an animal
Tom is an animal
Generic is an animalتمثّل الوراثة علاقة «هو نوع من»: فالكلب حيوان، وحساب التوفير حساب. عندما يستخدم صنفٌ صنفًا آخر فحسب (سيارة تحتوي على محرك)، أضف إليه خاصية من ذلك النوع بدلًا من ذلك. الأصناف مغلقة افتراضيًا في Kotlin، لذا يصرّح الصنف المخصّص للامتداد عن ذلك باستخدام open، بينما يظل سلوك كل صنف آخر محميًا من الأصناف الفرعية.
open class Account(val owner: String)
class SavingsAccount(owner: String) : Account(owner) // هو نوع من: الوراثة
class Engine(val horsepower: Int)
class Car(val engine: Engine) // يملك: خاصيةالتحدي
سهليكرر Manager ما لدى Employee بالفعل. اجعل Employee مفتوحًا وحوّل Manager إلى فئته الفرعية: تمرر Manager(name: String, salary: Int) القيمتين إلى Employee وتحتفظ فقط بما هو جديد، أي قائمة خاصة بأسماء التقارير مع addReport(name) وteamSize(). في Employee، تزيد raise(percent) الراتب بتلك النسبة، مع التقريب إلى الأسفل، وتُرجع Ada earns 5500.
ينشئ الكود المقدم مديرًا من السطر الأول (name,salary)، ويضيف كل اسم تالٍ كتقرير، ويمنحه زيادة قدرها 10% ويطبع Ada earns 5500 and leads 2، ثم يتحقق من أن المدير هو Employee.
ضع الكود الخاص بك في Employee.kt وManager.kt. يحتوي Main.kt على كود الإدخال/الإخراج المقدم ولا يمكن تعديله.
جرّب بنفسك
fun main() {
// كود الإدخال والإخراج المقدم: اتركه كما هو
val input = generateSequence(::readLine).toList()
val (name, salary) = input[0].split(",")
val boss = Manager(name, salary.toInt())
for (report in input.drop(1)) boss.addReport(report)
boss.raise(10)
println("${boss.describe()} and leads ${boss.teamSize()}")
println("a manager is an employee: ${(boss as Any) is Employee}")
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتالمنشئات الأساسيةكتل init والتحقق من الصحةالمنشئات الثانويةمراجعة - بطاقة المكتبة4الوراثة
الأصناف المفتوحة والأصناف الفرعيةتجاوز الأعضاءsuper والمنشئاتالأصناف المجرّدةمراجعة - دليل الموظفينتدرّب بنفسك: Playground لـ Kotlin