Что такое полиморфизм? И почему стоит учиться

Если вы умеете водить 4-дверный пригородный автомобиль, вы также можете водить пикап. Если вы управляли автомобилем с двигателем внутреннего сгорания, вы также можете водить электромобиль.

Форма и размер легковых автомобилей могут отличаться от одного к другому. Двигатель, которым управляют эти машины, тоже может быть совершенно другим. Но для водителя это не имеет значения.

Вы просто садитесь, пристегиваетесь, заводите автомобиль, включаете передачу и едете. Это потому, что автомобили, грузовики и фургоны полиморфны .

Полиморфизм: разрушение

Давайте посмотрим на слово полиморфизм. Вы можете разбить это на поли , морфинг и изм .

Поли означает много, как многоугольник означает много углов. При использовании в качестве существительного морф является вариантом вида. А изм может означать систему.

Таким образом, полиморфизм просто означает систему множества вариаций. Однако это все еще мало что говорит о том, как это используется в программировании. Это дальше.

Если он ходит как утка … Почему полиморфные объекты прекрасны

Когда вы создаете в своем коде класс, наследующий от другого класса, вы привязываете новый класс к контракту. В контракте указано, что каждая переменная и функция в родительском элементе также будет в дочернем.

В каждом автомобиле есть рулевое колесо, педали газа и тормоза, а также указатель поворота. Чтобы водить машину, не нужно открывать капот. Важно только то, что это машина.

То же самое относится к классам, которые наследуются от других классов. Вот пример на TypeScript:

 
class Vehicle {
private _engine: string;
private _tires: number;
constructor(engine: string = "combustion", tires: number = 4) {
this._engine = engine;
this._tires = tires;
}
accelerate(velocity: number) {
console.log("accelerating at a velocity of " + velocity);
}
brake(pressure: number) {
console.log("applying " + pressure + " pressure");
}
turnLeft() {
console.log("turning left");
}
turnRight() {
console.log("turning right");
}
}
class Car extends Vehicle {
}
class Tesla extends Car {
constructor() {
super("electric");
}
}

В этом примере есть класс Vehicle . Класс Car наследуется от класса Vehicle . И Tesla унаследовала от Car . Теперь давайте создадим пару объектов и посмотрим на них.

 let myCoupe: Car = new Vehicle();
console.log(myCoupe);
console.log(myCoupe.constructor.name);
let mySedan: Vehicle = new Tesla();
console.log(mySedan);
console.log(mySedan.constructor.name);
myCoupe.turnLeft();
mySedan.turnLeft();

Как видите, мы объявили myCoupe автомобилем, а mySedanтранспортным средством . Затем мы создали myCoupe как новый автомобиль, а mySedan как новый Tesla . Если вы посетите песочницу TypeScript и запустите код, вы увидите, что он работает без ошибок . И ведет себя так, как и следовало ожидать, в соответствии с контрактом.

Другими словами, все автомобили могут повернуть налево, потому что они унаследовали его от класса Vehicle . Компилятор знает, что каждый дочерний элемент Vehicle согласился с контрактом. Таким образом, предполагается, что все в порядке, независимо от того, в каких классах были типизированы объекты или созданы их экземпляры.

Иногда это называют «утиным набором текста». Компилятор предполагает, что если он ходит как утка и разговаривает как утка, то с таким же успехом он может быть уткой. Таким образом, компилятор не заботится о деталях и просто обращается с объектом как с уткой.

Полиморфизм делает ваш код пуленепробиваемым

Еще одно преимущество контракта полиморфизма – гарантия того, что ваш код будет работать. Если вы строго типизировали все свои переменные и то, что возвращает каждая функция, вы знаете, что каждый дочерний элемент всегда будет соответствовать переменным, функциям и типам.

Это означает, что вы можете добавлять и изменять код в своих классах, не нарушая свою программу. Каждый объект, который ссылается на объект Vehicle , всегда будет получать данные и функциональность, которые соответствуют ожиданиям, независимо от того, насколько сильно изменится Car .

Код внутри функции может не выдавать правильные результаты. Но это проблема другого рода. Пока функция следует контракту и возвращает ожидаемый тип переменной, это не приведет к нарушению кода.

Полиморфизм огромен, и вот еще 10 принципов программирования, которые вам следует знать .

Практика полиморфизма

  • Используйте ссылку на песочницу выше, чтобы создать класс Boat .
  • Создайте экземпляр нового объекта лодки таким образом, чтобы он был типом Vehicle , но по-прежнему выглядел как лодка.
  • Убедитесь, что лодка по-прежнему ведет себя как транспортное средство.

Последний пример полиморфизма

Полиморфизм может быть сложной задачей для понимания на начальном этапе. Но как только вы это усвоите, вы сделали огромный шаг к пониманию того, что такое объектно-ориентированное программирование на самом деле. Однако концепция может показаться теоретической. Итак, вот убедительный пример из реальной жизни, который поможет вам понять, насколько это полезно.

Представьте, что вы создаете веб-приложение, которое подключается к базе данных MySQL. Затем босс решает перейти на базу данных PostgreSQL. Означает ли это, что вам нужно переписать все обращения к базе данных?

Нет, это не так. Если ваше приложение использует класс DataAccess с подклассами, которые фактически возятся с данными, вам повезло. Класс DataAccess определяет, как ваше приложение взаимодействует с данными, а не то, как оно взаимодействует с базой данных.

У вас есть подклассы, такие как MySQLAccess и PostgresQLAccess, которые делают всю грязную работу. Но если в вашем приложении есть только объекты DataAccess , вы можете заменять базы данных, не переписывая ни одной строчки кода приложения.