final and Hierarchies
Part of the Object Oriented Programming section of Coddy's Swift journey. Lesson 25 of 57.
final stops further overriding. A final func cannot be overridden in any subclass, and a final class cannot be subclassed at all:
class Account {
final func id() -> String { "ACC" } // cannot be overridden
}
final class Receipt { } // cannot be subclassed
// class GiftReceipt: Receipt { } // error: inheritance from a final classMark a method final when subclasses must not change it, for example a method that enforces a rule. Other methods can still be overridden to customise details:
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]))Output:
100
90Hierarchies can have several levels. A method is looked up from the object's own class upwards, and the first implementation found runs:
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())Output:
swims
eatsKeep hierarchies shallow. Deep chains are hard to follow, because the behaviour of one object is spread over many classes. When types share behaviour without an is-a relation, protocols (next chapter) are usually the better tool.
// deep and fragile
class A { }
class B: A { }
class C: B { }
class D: C { } // what does D inherit, and from where?Challenge
EasyDiscount has a final method apply(to:) that returns the price minus amount(for:) but never below 0, and amount(for:) returns 0. Declare PercentOff (stored percent, amount = price times percent / 100) and FixedOff (stored value, amount = value), each with an initializer and an override of amount(for:). apply(to:) itself stays in Discount.
The supplied code reads the price and then discounts p,10 or f,300, applies each to the price and prints 1000 -> 900.
Your code goes in Discount.swift, PercentOff.swift and FixedOff.swift. main.swift holds the supplied input/output code and cannot be edited.
Try it yourself
// Supplied input/output code: keep it as it is
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))")
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesMethods and selfInitializersClasses Are ReferencesRecap - Library Card4Encapsulation
Access ControlRead-Only From OutsideGuarding StateFailable InitializersRecap - Bank Account7Polymorphism and Generics
PolymorphismType CastingGeneric FunctionsGeneric TypesRecap - Shape Calculator5Inheritance
SubclassesOverriding MethodsInitializers and superfinal and HierarchiesRecap - Employee Hierarchy11Project: Library Management
Books and MembersBorrowing BooksPractice on your own: Swift playground