@pgamesorg

Для чего нужен полиморфизм?

Я понял что такое:
Инкапсуляция — Наследование — Полиморфизм — Абстракция

Я понял для чего:
Инкапсуляция — Наследование — Абстракция

Но я не понял зачем и для чего — ПОЛИМОРФИЗМ

И не понимаю суть примеров которые приводят:
Создают новую функцию в которую помещается вызов определенного метода...
А ведь я могу и без написания доп функции обращаться к ее методу и исходя из примера так даже кода будет меньше.
  • Вопрос задан
  • 3463 просмотра
Решения вопроса 2
bingo347
@bingo347
Crazy on performance...
Полиморфизм бывает разный:
Полиморфизм подтипов - этот тип как раз таки и подразумевают в контексте ООП. Суть в том, что сущность некоторого класса так же может представляться базовым классом или интерфейсом. Это позволяет переиспользовать код, отдавая в один и тот же метод/функцию сущности с разными классами, но с общим интерфейсом.
Параметрический полиморфизм - используется уже не только в ООП, но и в других парадигмах. Опять таки полиморфная функция принимает аргумент разных типов, при этом сам тип так же передается как параметр функции, а следовательно функция может оперировать составными типами на основе переданного. Или например возвращать результат того же или производного типа, сохраняя тем самым тип для вызывающего кода. Чаще всего представлено дженериками, но могут быть и другие формы (например template в C++). Как правило не имеет смысла в языках с динамической типизацией. А еще часто сопровождается контрактами на получаемый тип (например типами высшего порядка или типажами), что позволяет с одной стороны ограничить возможные типы, а с другой - воспользоваться характеристиками типа обусловленными контрактом.
ad-hoc полиморфизм - способность функции предоставить разную реализацию в зависимости от запрашиваемой сигнатуры. Чаще всего выражено перегрузкой функций/методов. Как правило не реализуем средствами языка с динамической типизацией, хотя может быть реализован в рантайме (например в js функция всегда принимает произвольное количество аргументов и может проанализировать их в рантайме с помощью arguments).

В общем случае полиморфизм нужен для переиспользования кода. Соблюдения практик SOLID и DRY не возможно без полиморфизма. Например в языке Go отсутствие полиморфизма в любом виде приводит к загрязнению кодовой базы и большому количеству копипасты.

И еще, из моего ответа, может сложится мнение, что полиморфизм не применим к языкам с динамической типизацией, например к Python. На самом деле это не так, в ЯП с динамической типизацией полиморфизм наоборот возведен в абсолют.

UPD: Примеры:
правда я не шибко хорошо знаю конкретно Python, поэтому абстрактно напишу псевдокод:

Полиморфизм подтипов, как уже говорил, это про ООП. Допустим у меня задача реализовать класс, который читает бинарные данные, проверяет, что они валидный utf-8 и выдает прочитанное как строку. Откуда он читает их? Да мне все равно, это не относятся к моей задаче. Конкретную реализацию я приму в аргументах, а уж откуда она будет читать, из файла или из сети - мне все равно. Главное чтоб эта реализация умела читать байты.
// ok мне нужно что-то, что умеет читать байты, опишу это интерфейсом
interface IByteReader {
  readBytes(): BytesIterator;
}

// и мой метод:
readAsString(reader: IByteReader): string {
  var iterator: BytesIterator = reader.readBytes();
  // ну и тут как то с ним работаю, трансформируя байты в строку
}
теперь вызывающий код может передать в мой метод инстанс любого класса, реализующего мой интерфейс, и мне теперь не нужно дублировать логику чтения строки для файла и для сети.
Еще один яркий пример тут - функция len() в Python, которая принимает любой тип реализующий одноименный магический метод.

Параметрический полиморфизм, это про дженерики. Напишем 2 функции, обе будут принимать на вход массив, одна из них будет возвращать начальный элемент, а другая конечный. Но массивы бывают для элементов разных типов. Без параметрического полиморфизма, нам бы пришлось писать реализацию для каждого нужного типа, но благодаря ему мы можем это сделать в обобщенном виде:
// T - это параметр типа
fitst<T>(arr: [T]): Option<T> {
  if(arr.has(0)) return Some(arr[0]);
  else return None;
}

// давайте предположим, что некоторые виды массивов у нас могут быть бесконечными
// тогда нам понадобится контракт, что можно передавать массивы только с известным размером
last<T>(arr: [T]): Option<T>
  where [T]: WithKnownSize
{
  var length: size = get_length(arr);
  if(length == 0) return None;
  else return arr[length - 1];
}


ad-hoc полиморфизм, это про перегрузку функций, пусть мы хотим функцию print которая умеет печатать числа и строки:
print(value: string) {
  stdout.write(value);
}
print(value: int) {
  stdout.write(value.to_string());
}
Ответ написан
trapwalker
@trapwalker Куратор тега Python
Программист, энтузиаст
Полиморфизм - это широкое понятие.
Идея его в том, чтобы скрыть лишние детали реализации и сделать код более универсальным.
К примеру у вас есть абстрактный класс Фигура, у него есть абстрактный метод нарисовать(куда: Канва). Этот метод нельзя запускать, он абстрактный. Не понятно как рисовать абстрактную фигуру.
Зато у фигуры есть потомки: Круг(Фигура) и Квадрат(Фигура). У них метод "нарисовать" перекрыт конкретной реализацией. Это виртуальный метод (есть такой термин в некоторых ЯП).
За счет полиморфизма мы можем нарисовать любую фигуру не зная как она рисуется. Мы знаем только как с ней общаться на уровне ее интерфейса.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
solotony
@solotony
покоряю пик Балмера
для того что бы в подобной ситуации

класс1.метод
класс2.метод


имея ссылку на объект (и не зная что это) выполнить вызов

объект.метод()
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы