Menu
Coddy logo textTech

オープンクラスとサブクラス

CoddyのKotlinジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 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 ball

class Dog(name: String) : Animal(name)は、DogがAnimalを継承し、nameをスーパークラスのコンストラクターに渡すことを示しています。プロパティはすでにAnimalに存在するため、パラメーターにはvalがありません。openでないクラスは継承できません。

class Plant(val name: String)
// class Tree(name: String) : Plant(name)   // error: この型は final なので拡張できません

open class Vehicle(val wheels: Int)
class Bike : Vehicle(2)                     // 固定値を渡す
class Truck(val load: Int) : Vehicle(6)     // 独自のプロパティを追加する

Dog は Animal なので、サブクラスのインスタンスはスーパークラス型が期待される場所で使用できます。1つの 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

継承は is-a 関係をモデル化します。犬は動物であり、普通預金口座は口座です。あるクラスが別のクラスを使用するだけの場合(車がエンジンを持つなど)は、代わりにその型のプロパティを持たせます。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: プロパティ
challenge icon

チャレンジ

簡単

Manager は Employee がすでに持っているものを繰り返しています。Employee を open にし、Manager をそのサブクラスにしてください。Manager(name: String, salary: Int) は両方の値を Employee に渡し、新しい部分だけを保持します。それは、addReport(name) と teamSize() を備えた、報告者名の private リストです。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}")
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Kotlinプレイグラウンド