Чем абстрактный класс отличается от интерфейса?
Суть
Абстрактный класс — класс, экземпляр которого нельзя создать: часть методов объявлена без тела, часть реализована, есть хранимые поля и конструкторы. Интерфейс — чистый контракт без состояния; тип может реализовать несколько интерфейсов, но наследовать только один класс.
Классическое различие (Java/C#):
- Абстрактный класс: одиночное наследование, может хранить состояние, конструкторы, любые модификаторы доступа, частичная реализация.
- Интерфейс: множественная реализация, нет хранимого состояния; с Java 8 / C# 8 допускает default-методы, а свойства в интерфейсах есть и в C#, и в Swift.
Старый ответ «интерфейс содержит только объявления и не может иметь свойств» устарел.
В Swift абстрактных классов нет
Ключевое слово abstract отсутствует. Варианты:
import Foundation
// 1. Protocol with a default implementation — the Swift way.
protocol Exporter {
var fileExtension: String { get } // "abstract" member
func serialize(_ text: String) -> Data
}
extension Exporter {
func export(_ text: String) -> String { // shared "concrete" method
"report.\(fileExtension) (\(serialize(text).count) bytes)"
}
}
struct TextExporter: Exporter {
let fileExtension = "txt"
func serialize(_ text: String) -> Data { Data(text.utf8) }
}
print(TextExporter().export("hi")) // report.txt (2 bytes)
// 2. Emulated abstract class: crashes at runtime instead of compile time.
class AbstractExporter {
func serialize(_ text: String) -> Data {
fatalError("subclass must override")
}
}
- Протокол +
extensionпокрывает 90% случаев: обязательные требования проверяет компилятор, общий код лежит в extension, принимать могут и структуры. - Если нужно общее хранимое состояние для подклассов — базовый класс с
fatalError()в «абстрактных» методах. Минус: забытыйoverrideобнаружится только в рантайме. - Комбинация: протокол задаёт контракт, базовый класс даёт состояние и принимает протокол.
На что смотрит интервьюер
- Умение сказать: «в Swift я беру протокол; абстрактный класс — только когда нужны хранимые свойства и наследование от фреймворкового класса».
- Понимание, что протокол не может иметь хранимых свойств в
extension— только вычисляемые. - Знание, что
UIViewControllerс методами «для переопределения» — это фактически абстрактный класс в стиле UIKit.