Ответ
В Swift протокол определяет контракт (интерфейс), а абстрактный класс — это шаблон для наследования, который сам по себе языком не поддерживается напрямую, но эмулируется. Вот ключевые различия:
Сравнительная таблица
| Критерий | Протокол (Protocol) | Абстрактный класс (Эмуляция) |
|---|---|---|
| Наследование | Поддерживает множественное наследование (тип может соответствовать многим протоколам). | Поддерживает только одиночное наследование. |
| Кто может использовать | Классы, структуры (struct), перечисления (enum). |
Только классы. |
| Реализация по умолчанию | Есть через расширения (extension). |
Может содержать реализованные и абстрактные (нереализованные) методы в одном классе. |
| Хранимые свойства | Не может иметь хранимые свойства, только требования. | Может иметь хранимые свойства. |
| Инициализаторы | Может требовать инициализатор (init), но не может его реализовать. |
Может иметь назначенные и convenience инициализаторы. |
| Тип-значение / ссылка | Агностичен (работает и со value, и с reference типами). | Работает только с reference типами (классами). |
Примеры
// 1. Протокол с расширением для реализации по умолчанию
protocol Vehicle {
var fuelLevel: Double { get set }
func startEngine() // Требование
}
extension Vehicle {
func startEngine() { // Реализация по умолчанию
print("Engine started for a generic vehicle.")
}
}
struct Car: Vehicle {
var fuelLevel: Double
// startEngine() можно не реализовывать, используется дефолтная версия
}
// 2. Эмуляция абстрактного класса
class AbstractShape {
// "Абстрактный" метод - требует переопределения
func area() -> Double {
fatalError("Subclass must override area()")
}
// Конкретный метод
func description() -> String {
return "Shape with area: (area())"
}
}
class Square: AbstractShape {
let side: Double
init(side: Double) { self.side = side }
override func area() -> Double { // Обязательное переопределение
return side * side
}
}
// let shape = AbstractShape() // Вызовет fatalError
let square = Square(side: 5)
print(square.description()) // "Shape with area: 25.0"
Вывод: Протоколы в Swift более гибкие и являются предпочтительным способом определения интерфейсов и поведения (протокол-ориентированное программирование). Абстрактные классы используются реже, в основном когда нужна общая базовая реализация с хранимым состоянием для иерархии классов.