Что такое полиморфизм в объектно-ориентированном программировании?

«Что такое полиморфизм в объектно-ориентированном программировании?» — вопрос из категории Основы программирования, который задают на 10% собеседований QA Тестировщик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Полиморфизм — это принцип ООП, позволяющий объектам разных классов обрабатываться как объекты общего родительского класса, при этом конкретное поведение (вызываемый метод) определяется реальным типом объекта во время выполнения.

Суть: «Один интерфейс — множество реализаций». Код может работать с абстракцией, не зная конкретного типа объекта.

Основные типы полиморфизма:

  1. Полиморфизм подтипов (на основе наследования): Самый распространённый вид.
  2. Параметрический полиморфизм (дженерики/шаблоны): Код, работающий с разными типами данных.

Пример на Python (полиморфизм подтипов):

from abc import ABC, abstractmethod

# Абстрактный базовый класс (интерфейс)
class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

# Конкретные реализации
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area(self):
        return self.width * self.height

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return 3.14 * self.radius ** 2

# Функция, использующая полиморфизм
def print_area(shape: Shape):  # Принимает любой объект типа Shape
    print(f"Площадь фигуры: {shape.area()}")

# Создание объектов
rect = Rectangle(5, 10)
circle = Circle(7)

# Один вызов функции для разных типов
print_area(rect)   # Выведет: Площадь фигуры: 50
print_area(circle) # Выведет: Площадь фигуры: 153.86

Функция print_area не знает, с Rectangle или Circle она работает. Она вызывает метод area(), а конкретная реализация выбирается в рантайме на основе типа объекта.

Пример параметрического полиморфизма (дженерики в Java):

// Класс, работающий с любым типом T
public class Box<T> {
    private T content;
    public void set(T content) { this.content = content; }
    public T get() { return content; }
}

Box<String> stringBox = new Box<>();
stringBox.set("Hello");
Box<Integer> intBox = new Box<>();
intBox.set(123);
// Один класс Box, но разное поведение для String и Integer

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