Полиморфизм
Привет! Прежде чем мы перейдём к принципу O (Open-Closed), давай разберём одно важное понятие, без которого он не работает — полиморфизм.
Полиморфизм — это один из трёх “китов” объектно-ориентированного программирования (вместе с инкапсуляцией и наследованием).
Звучит страшно? На самом деле всё просто.
Полиморфизм — это способность объектов с одинаковым интерфейсом вести себя по-разному.
Пример из жизни
Представь, что у тебя есть универсальный пульт управления. На нём есть кнопка “Воспроизвести”.
- Если нажать её на телевизоре — он включит канал.
- Если нажать на музыкальном центре — он включит музыку.
- Если нажать на плеере — он запустит фильм.
Одна и та же кнопка работает по-разному на разных устройствах. Это и есть полиморфизм.
Полиморфизм в коде
В программировании полиморфизм позволяет нам писать код, который работает с абстракциями, а не с конкретными типами.
Вот простой пример на TypeScript:
export type Animal = {
makeSound(): void;
};
export class Dog implements Animal {
public makeSound(): void {
return console.log("Woof!");
}
}
export class Cat implements Animal {
public makeSound(): void {
return console.log("Meow!");
}
}
export class Cow implements Animal {
public makeSound(): void {
return console.log("Moo!");
}
}
const makeAnimalSound = (animal: Animal): void => {
return animal.makeSound();
};
const dog = new Dog();
const cat = new Cat();
const cow = new Cow();
makeAnimalSound(dog); // Woof!
makeAnimalSound(cat); // Meow!
makeAnimalSound(cow); // Moo!Что здесь произошло?
- Мы создали интерфейс
Animalс методомmakeSound(). - Каждый класс (
Dog,Cat,Cow) по-своему реализует этот метод. - Функция
makeAnimalSoundпринимает любой объект, который реализуетAnimal. Она не знает, кто именно к ней придёт, но уверена, что методmakeSound()у объекта есть. - Когда мы вызываем
animal.makeSound(), вызывается нужная реализация — та, которая принадлежит конкретному объекту.
Это и есть полиморфизм: один интерфейс, много реализаций.
Зачем это нужно?
Полиморфизм даёт нам суперспособность:
Мы можем писать код, который работает с будущими классами, которые ещё не написаны.
Как это?
Представь, что ты пишешь библиотеку для работы с животными.
Ты не знаешь, каких животных будет создавать программист, использующий твою библиотеку.
Но если ты предоставишь интерфейс Animal, программист сможет создать класс Elephant или Penguin,
реализовать makeSound(), и твоя библиотека будет работать с ними без изменений!
export class Elephant implements Animal {
public makeSound(): void {
console.log("Trumpet!");
}
}
const elephant = new Elephant();
makeAnimalSound(elephant); // Trumpet!Полиморфизм и SOLID
Полиморфизм — это основа для двух принципов SOLID:
- O (Open-Closed Principle): Мы можем расширять систему новыми классами, не изменяя существующий код, именно благодаря полиморфизму.
- L (Liskov Substitution Principle): Мы можем заменять родительский класс на наследника, потому что наследник реализует тот же интерфейс (или расширяет родителя).
Без полиморфизма эти принципы были бы невозможны.
Как это выглядит на практике?
Чаще всего полиморфизм используют, чтобы избавиться от условных операторов (if/else, switch).
Вместо того чтобы проверять тип объекта и выполнять разную логику, мы просто вызываем метод через общий интерфейс.
Без полиморфизма:
const makeSound = (animal: any): void => {
if (animal.type === "dog") {
return console.log("Woof!");
}
if (animal.type === "cat") {
return console.log("Meow!");
}
if (animal.type === "cow") {
return console.log("Moo!");
}
throw new Error("Bad animal.");
};С полиморфизмом:
export type Animal = {
makeSound(): void;
};
const makeSound = (animal: Animal): void => {
return animal.makeSound();
};Как видишь, полиморфизм делает код чище, гибче и открытым для расширения.
Итог
- Полиморфизм — это способность объектов с одинаковым интерфейсом вести себя по-разному.
- Он позволяет писать код, который работает с абстракциями, а не с конкретными реализациями.
- Это основа для принципов O и L в SOLID.
- На практике полиморфизм помогает избавиться от
if/elseи делает код более гибким.