Полиморфизм
Возможность работать с разными объектами через один общий интерфейс: код вызывает метод, а что именно произойдет, решает сам объект.
Полиморфизм (от греческого «многообразие форм») — принцип, при котором один и тот же вызов работает с объектами разных типов, и каждый объект выполняет его по-своему. Код оформления заказа просто говорит «оплатить», а как именно пройдет оплата — картой, через СБП или по счету, — решает выбранный способ оплаты.
Пример
// Kotlin
interface PaymentMethod {
fun pay(amount: Long)
}
class CardPayment : PaymentMethod {
override fun pay(amount: Long) { /* списание с банковской карты */ }
}
class SbpPayment : PaymentMethod {
override fun pay(amount: Long) { /* перевод через СБП */ }
}
fun checkout(method: PaymentMethod, amount: Long) = method.pay(amount)
Функция checkout на Kotlin не знает и не должна знать, какие бывают способы оплаты. Когда появится оплата по счету, достаточно добавить новый класс — checkout и все, что ее вызывает, менять не придется.
Виды полиморфизма
- Через общий интерфейс или наследование — как в примере выше: разные классы реализуют один интерфейс. Это то, что обычно имеют в виду в ООП.
- Параметрический — один код работает с любым типом данных: список
List<T>одинаково хранит и строки, и заказы. Это обобщенные типы (generics). - Специальный — перегрузка: несколько функций с одним именем для разных типов аргументов, например сложение чисел и сложение строк.
Зачем это нужно
- Расширение без переделки. Новое поведение добавляется новым классом, а работающий код не трогают. Это один из принципов хорошего проектирования: код открыт для расширения, но закрыт для изменения.
- Меньше условий. Вместо длинных цепочек «если карта — то так, если СБП — то так» в одном месте каждый вариант живет в своем классе.
- Проще тестировать. В тестах вместо настоящей оплаты подставляют тестовую реализацию того же интерфейса.
Связь с другими понятиями
Полиморфизм работает в паре с инкапсуляцией: объект скрывает, как он выполняет действие, а полиморфизм позволяет вызывать это действие одинаково для всех. На нем построены многие шаблоны проектирования — Стратегия, Команда, Наблюдатель. А в языках с динамической типизацией, например Python, полиморфизм работает и без общих интерфейсов: достаточно, чтобы у объекта был нужный метод («утиная типизация»).