מחלקות פתוחות ותת-מחלקות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-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) // is-a: ירושה
class Engine(val horsepower: Int)
class Car(val engine: Engine) // has-a: מאפייןאתגר
קלManager חוזרת על מה שכבר יש ב־Employee. הפכו את Employee לפתוחה והפכו את Manager לתת־מחלקה שלה: Manager(name: String, salary: Int) מעבירה את שני הערכים ל־Employee ומשאירה רק את מה שחדש — רשימה פרטית של שמות העובדים המדווחים לה, עם addReport(name) ו־teamSize(). ב־Employee, הפונקציה raise(percent) מגדילה את המשכורת באחוז הנתון, בעיגול כלפי מטה, ו־describe() מחזירה את 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 ואימות נתוניםבנאים משנייםסיכום – כרטיס ספרייהתרגלו בעצמכם: Kotlin אונליין