Menu
Coddy logo textTech

Dynamiczne wiązanie

Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 27 z 57.

Polimorfizm oznacza, że jedno wywołanie może działać na wiele sposobów. Gdy wywołujesz przesłoniętą metodę za pośrednictwem typu nadklasy lub interfejsu, Kotlin sprawdza rzeczywistą klasę obiektu podczas działania programu i wykonuje wersję tej klasy. To jest dynamiczne wiązanie:

abstract class Animal(val name: String) {
    abstract fun sound(): String
    fun speak() = "$name: ${sound()}"
}
class Dog(name: String) : Animal(name) {
    override fun sound() = "Woof"
}
class Cow(name: String) : Animal(name) {
    override fun sound() = "Moo"
}

Wewnątrz main:

val barn: List<Animal> = listOf(Dog("Rex"), Cow("Bess"), Dog("Fido"))
for (a in barn) println(a.speak())

Wynik:

Rex: Woof
Bess: Moo
Fido: Woof

Kod wywołujący nie zmienia się, gdy pojawia się nowa podklasa. Poniższa funkcja totalArea została napisana z myślą o dowolnym Shape, więc działa również z Triangle, mimo że nikt jej nie zmieniał:

interface Shape {
    fun area(): Double
}
class Square(val side: Double) : Shape {
    override fun area() = side * side
}
class Triangle(val base: Double, val height: Double) : Shape {
    override fun area() = base * height / 2
}

fun totalArea(shapes: List<Shape>) = shapes.sumOf { it.area() }

Wewnątrz main:

println(totalArea(listOf(Square(2.0), Triangle(3.0, 4.0))))

Wynik:

10.0

Wysyłanie wywołania zależy od obiektu, a nie od zmiennej. Przypisanie innego obiektu do tej samej zmiennej zmienia, który kod zostanie uruchomiony przy następnym wywołaniu:

interface Mode {
    fun format(text: String): String
}
class Normal : Mode {
    override fun format(text: String) = text
}
class Shout : Mode {
    override fun format(text: String) = text.uppercase() + "!"
}

Wewnątrz main:

var mode: Mode = Normal()
println(mode.format("hello"))
mode = Shout()
println(mode.format("hello"))

Wynik:

hello
HELLO!

Polimorfizm zastępuje sprawdzanie warunków, takich jak if (kind == "dog"), które w przeciwnym razie trzeba by powtarzać wszędzie tam, gdzie używane są zwierzęta. Każda klasa zachowuje własne zachowanie, a dodanie nowego rodzaju zwierzęcia oznacza dodanie jednej klasy:

// bez polimorfizmu: każda funkcja sprawdza typ
fun sound(kind: String) = when (kind) { "dog" -> "Woof"; "cow" -> "Moo"; else -> "?" }

// z polimorfizmem: nowy typ ma własne zachowanie
class Sheep(name: String) : Animal(name) {
    override fun sound() = "Baa"
}
challenge icon

Wyzwanie

Łatwy

Character(name, hp) jest klasą open. takeHit(damage) odejmuje obrażenia od hp (nigdy nie schodzi poniżej 0), a status() zwraca Ada: 30 hp lub Ada: down przy wartości 0. Wartość hp można odczytać z dowolnego miejsca, ale zmieniać ją można tylko wewnątrz Character. Uzupełnij podklasy, nadpisując takeHit i przekazując zmienione obrażenia do super.takeHit: Warrior (40 hp) otrzymuje połowę obrażeń, zaokrągloną w dół; Mage (25 hp) ma tarczę, która pochłania całe obrażenia z pierwszego trafienia; Rogue (30 hp) unika co drugiego otrzymanego trafienia (2., 4. itd.).

Dostarczony kod wczytuje drużynę w postaci warrior:Ada,mage:Bo,rogue:Cy, a następnie zadaje obrażenia za pomocą all 10 lub Ada 12. Wywołuje takeHit za pośrednictwem typu Character, a na końcu wyświetla każdy wynik status().

Twój kod umieść w plikach Character.kt, Warrior.kt, Mage.kt i Rogue.kt. Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

fun main() {
    // Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
    val input = generateSequence(::readLine).toList()
    val party = input[0].split(",").map { spec ->
        val (kind, name) = spec.split(":")
        when (kind) {
            "warrior" -> Warrior(name)
            "mage" -> Mage(name)
            else -> Rogue(name)
        }
    }
    for (cmd in input.drop(1)) {
        val (target, damage) = cmd.split(" ")
        for (c in party) {
            if (target == "all" || target == c.name) c.takeHit(damage.toInt())
        }
    }
    for (c in party) println(c.status())
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Edytor online Kotlin