final и иерархии
Часть раздела Объектно-ориентированное программирование путешествия по Swift на Coddy. Урок 25 из 57.
final запрещает дальнейшее переопределение. final func нельзя переопределить ни в каком подклассе, а final class вообще нельзя сделать суперклассом:
class Account {
final func id() -> String { "ACC" } // не может быть переопределён
}
final class Receipt { } // не может быть унаследован
// class GiftReceipt: Receipt { } // ошибка: наследование от final-классаПометьте метод как final, если подклассы не должны изменять его, например метод, который обеспечивает соблюдение правила. Другие методы по-прежнему можно переопределять, чтобы настраивать детали:
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]))Вывод:
100
90Иерархии могут иметь несколько уровней. Метод ищется начиная с собственного класса объекта и далее вверх, и выполняется первая найденная реализация:
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())Вывод:
swims
eatsСтарайтесь, чтобы иерархии были неглубокими. За глубокими цепочками трудно следить, поскольку поведение одного объекта распределено между множеством классов. Когда типы совместно используют поведение без отношения «является», протоколы (следующая глава) обычно являются более подходящим инструментом.
// глубокое и хрупкое
class A { }
class B: A { }
class C: B { }
class D: C { } // что наследует D, и откуда?Задание
ЛегкоУ Discount есть метод final apply(to:), который возвращает цену за вычетом amount(for:), но результат не может быть меньше 0, а amount(for:) возвращает 0. Объявите PercentOff (с хранимым свойством percent, сумма = цена, умноженная на percent / 100) и FixedOff (с хранимым свойством value, сумма = value), каждый с инициализатором и переопределением amount(for:). Сам apply(to:) должен оставаться в Discount.
Предоставленный код считывает цену, а затем применяет скидки p,10 или f,300, применяет каждую из них к цене и выводит 1000 -> 900.
Ваш код должен находиться в файлах Discount.swift, PercentOff.swift и FixedOff.swift. В main.swift находится предоставленный код ввода/вывода, и его нельзя изменять.
Попробуйте сами
// Предоставленный код ввода/вывода: оставьте его как есть
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))")
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовМетоды и selfИнициализаторыКлассы — это ссылкиПовторение — читательский билет4Инкапсуляция
Контроль доступаТолько чтение извнеЗащита состоянияИнициализаторы с возможностью сбояПовторение — банковский счёт7Полиморфизм и обобщения
ПолиморфизмПриведение типовОбобщённые функцииОбобщённые типыПовторение — калькулятор фигур10Паттерны проектирования. Часть 2
Паттерн делегированияПаттерн декораторПаттерн строительПаттерн состояния2Структуры и типы-значения
СтруктурыСемантика значенийИзменяющие методыСтруктура или классПовторение — элемент инвентаря5Наследование
ПодклассыПереопределение методовИнициализаторы и superfinal и иерархииПовторение — иерархия сотрудников8Стандартные протоколы
CustomStringConvertibleEquatableComparableHashableПовторение — пользовательская сортировка11Проект: Управление библиотекой
Книги и читателиВыдача книгПотренируйтесь самостоятельно: Песочница Swift