Наследование
Суть
Наследование — механизм, при котором класс получает свойства и методы родительского класса и может их расширять или переопределять. Это отношение «is-a»: Circle является Shape. Наследование даёт полиморфизм подтипов: там, где ожидается Shape, можно передать Circle.
В Swift
- Наследуются только классы;
struct,enumиactorне наследуются — они переиспользуют код через протоколы иextension. - Наследование одиночное: один суперкласс, сколько угодно протоколов.
overrideобязателен при переопределении,superвызывает родительскую реализацию,finalзапрещает наследование (и даёт компилятору статическую диспетчеризацию вместо vtable).- Инициализаторы: designated/convenience, двухфазная инициализация,
required initобязателен в подклассах.
class Shape {
func area() -> Double { 0 }
func describe() -> String { "area = \(area())" }
}
final class Circle: Shape {
let radius: Double
init(radius: Double) { self.radius = radius }
override func area() -> Double { .pi * radius * radius }
override func describe() -> String { "circle, " + super.describe() }
}
let shapes: [Shape] = [Circle(radius: 1), Shape()]
for s in shapes { print(s.describe()) }
// circle, area = 3.141592653589793
// area = 0.0
Плюсы и цена
- Плюс: меньше дублирования, готовая точка расширения (UIKit целиком построен на
UIView/UIViewController). - Минус: хрупкий базовый класс — изменение родителя ломает наследников; подкласс зависит от деталей реализации родителя, то есть наследование частично ломает инкапсуляцию.
- Глубокие иерархии трудно читать (поведение «размазано» по уровням) и тестировать.
- Правило проектирования: «предпочитайте композицию наследованию» — наследуйтесь, когда действительно нужно подменять поведение фреймворка или есть честное отношение is-a.