Вопрос проверяет понимание ключевых различий между двумя основными способами реализации полиморфизма в Swift и умение выбирать подходящий инструмент.
Полиморфизм через наследование строится на иерархии классов и переопределении методов. Полиморфизм через протоколы основан на контракте поведения и не требует общего предка. Протоколы позволяют гибче комбинировать поведение и лучше подходят для композиции. В Swift протоколы чаще предпочтительнее наследования. Это делает код более расширяемым и тестируемым.
В Swift есть два основных способа реализовать полиморфизм, и они решают похожие задачи, но разными путями.
Этот подход базируется на иерархии классов.
Как работает:
есть базовый класс
подклассы переопределяют поведение
вызов метода определяется во время выполнения
Плюсы:
хорошо подходит для UIKit
понятен и привычен
поддерживает общий state базового класса
Минусы:
жёсткая иерархия
один родительский класс
сложнее переиспользовать поведение
Протоколы описывают контракт, а не структуру.
Как работает:
тип реализует протокол
код работает с протоколом, а не с конкретным типом
типы не связаны иерархией
Плюсы:
нет жёсткой иерархии
можно реализовать несколько протоколов
проще комбинировать поведение
удобнее тестировать
Минусы:
есть нюансы с existential типами
иногда сложнее для новичков
Swift ориентирован на:
value types
композицию вместо наследования
протокол-ориентированное программирование
Это делает протоколы естественным инструментом для полиморфизма.
protocol Logger {
func log(_ message: String)
}
struct ConsoleLogger: Logger {
func log(_ message: String) { /* вывод в консоль */ }
}
Добавление нового логгера не требует изменения существующего кода.
Наследование подходит для случаев с общей природой объектов (особенно в UIKit), а протоколы — для гибкого и масштабируемого дизайна. В большинстве архитектурных решений в Swift предпочтение отдают протоколам.