Menu
Coddy logo textTech

final und Hierarchien

Teil des Abschnitts Objektorientierte Programmierung der Swift-Journey von Coddy. Lektion 25 von 57.

final verhindert weiteres Überschreiben. Eine final func kann in keiner Unterklasse überschrieben werden, und eine final class kann überhaupt nicht als Basisklasse verwendet werden:

class Account {
    final func id() -> String { "ACC" }   // kann nicht überschrieben werden
}

final class Receipt { }                  // kann nicht unterklassifiziert werden
// class GiftReceipt: Receipt { }        // error: Vererbung von einer finalen Klasse

Markiere eine Methode mit final, wenn Unterklassen sie nicht ändern dürfen, beispielsweise eine Methode, die eine Regel durchsetzt. Andere Methoden können weiterhin überschrieben werden, um Details anzupassen:

class Checkout {
    final func total(_ prices: [Int]) -> Int {
        let sum = prices.reduce(0, +)
        return sum - discount(sum)
    }
    func discount(_ sum: Int) -> Int { 0 }
}

class SaleCheckout: Checkout {
    override func discount(_ sum: Int) -> Int { sum / 10 }
}

print(Checkout().total([50, 50]))
print(SaleCheckout().total([50, 50]))

Ausgabe:

100
90

Hierarchien können mehrere Ebenen haben. Eine Methode wird von der eigenen Klasse des Objekts aufwärts gesucht, und die erste gefundene Implementierung wird ausgeführt:

class Animal {
    func move() -> String { "moves" }
    func eat() -> String { "eats" }
}
class Bird: Animal {
    override func move() -> String { "flies" }
}
class Penguin: Bird {
    override func move() -> String { "swims" }
}

let p = Penguin()
print(p.move())
print(p.eat())

Ausgabe:

swims
eats

Halte Hierarchien flach. Tiefe Ketten sind schwer nachzuvollziehen, weil das Verhalten eines Objekts über viele Klassen verteilt ist. Wenn Typen Verhalten ohne eine Is-a-Beziehung gemeinsam nutzen, sind Protokolle (nächstes Kapitel) meist das bessere Werkzeug.

// tief und fragil
class A { }
class B: A { }
class C: B { }
class D: C { }      // was erbt D, und von wo?
challenge icon

Aufgabe

Einfach

Discount verfügt über eine final-Methode apply(to:), die den Preis minus amount(for:) zurückgibt, jedoch niemals weniger als 0, und amount(for:) gibt 0 zurück. Deklariere PercentOff (gespeichertes percent, Betrag = Preis mal Prozent / 100) und FixedOff (gespeichertes value, Betrag = value), jeweils mit einem Initialisierer und einer Überschreibung von amount(for:). apply(to:) selbst bleibt in Discount.

Der bereitgestellte Code liest den Preis ein und wendet anschließend Rabatte in Form von p,10 oder f,300 an, wendet jeden davon auf den Preis an und gibt 1000 -> 900 aus.

Dein Code gehört in Discount.swift, PercentOff.swift und FixedOff.swift. main.swift enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

// Gelieferter Ein-/Ausgabecode: belasse ihn wie er ist
var input: [String] = []
while let line = readLine() { input.append(line) }
let price = Int(input[0])!
for line in input.dropFirst() {
    let p = line.split(separator: ",").map(String.init)
    let d: Discount = p[0] == "p" ? PercentOff(percent: Int(p[1])!) : FixedOff(value: Int(p[1])!)
    print("\(price) -> \(d.apply(to: price))")
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Swift-Playground