1

Учил джаву и никак не могу понять, зачем использовать полиморфизм, для чего делать, пустой класс скажем человека, объявлять пустые методы, а после этого создавать одного, второго, третьего и т.д. человека, используя класс человека? Не проще ли сразу создать классы людей? Ведь чтобы их использовать в любом случае придётся к ним обратится, так в чём суть?

Смотрел разные примеры, видео, но этот вопрос меня никак не покидает, вот к примеру последнее видео, которое я смотрел — youtu.be/...​uaF0s?si=MtKNlgzhXWW-MQCX

Здесь автор делает пример из доты, в котором делает с помощью полиморфизма из статической типизации — динамическую, ну как я понял.

А чем это поможет если по сути, класс Hero, имеет в себе классы всех персонажей, то есть по логике, когда с помощью него объявляется 5 переменных с героями, в каждой переменной нет конкретного героя, как понять кого надо вызвать именно? Как я понимаю уже в будущем коде надо это реализовать, но тогда каким образом понять какого героя надо выбрать? И в последующем, вызвать класс нужного героя, не лучше ли сразу определиться и вызвать нужные классы, вместо того чтобы вызывать все, а работать с определёнными? Или может я что-то не понимаю, в любом случае если у вас есть пример полиморфизма, в котором не возникнет вопрос, а нафига всё усложнять, то буду рад его прочитать, потому как что такое полиморфизм, и как он примерно работает я знаю, но не понимаю.

  • 4
    "не лучше ли сразу определиться и вызвать нужные классы" --- что значит сразу определиться? Опеределяться будет игрок. А вы без понятия кого он выберет. И вот для того чтобы метод например hit работал одинаково не зависимо от того кого выберет пользователь/игрок, а не разработчик, который понятия этого не имеет, и нужен общий интерфейс – Алексей Шиманский Nov 04 '23 at 15:15

2 Answers2

2

Максим! Полиморфизм - множество форм. Первое, что пришло в голову, это пример с животными. Создадим интерфейс животное (Animal).

interface Animal {
    String voice();
}

В нём только один метод, voice(), без определения поумолчанию. Так как животные могут быть разные, звуки они тоже издают разные и на данном уровне абстракции мы не знаем, конкретно какие животные будут реализовывать этот интерфейс. Потому нам не известно, какие звуки они будут издавать. Добавим классы каких-то животных, в моём случае их три: Cat, Dog, Mouse.

class Cat implements Animal {
@Override
public String voice() {
    return "Мяу, мяу..."; // Кошка мяукает
}

}

class Dog implements Animal {

@Override
public String voice() {
    return "Гав, гав..."; // Собака лает
}

}

class Mouse implements Animal {

@Override
public String voice() {
    return "Пи, пи..."; // Мышь пищит
}

}

Теперь создадим класс Main с методом main(), откуда и будет стартовать наша программа.

public class Main {
    public static void main(String[] args) {
        Animal[] animals = {
            new Dog(),
            new Cat(),
            new Mouse()
        };
    for (Animal animal : animals) {
        System.out.println(animal.getClass().getSimpleName() + ": " + animal.voice());
    }
}

}

В методе main() создаём массив типа Animal и добавляем в него наших животных, после чего в цикле проходимся по массиву и вы вводим их голоса в консоль. Обрати внимание, что массив у нас имеет тип Animal, т.е. тип интерфейса. Интерфейс как бы обязует каждый класс, который будет его реализовывать, создать свой метод voice(), который и будет возвращать нужный звук, в зависимости от того, какое именно животное его издаёт. Это и есть полиморфизм, точнее одно из его определений. Вообще в сети много ресурсов, где об этом можно почитать, более подробно. Если, что-то не понятно, уточняй, что именно.

e1st0rm
  • 46
  • 2
2

Хм, давайте на примере, который вы как раз и привели. Герои из Доты. Есть, скажем, абстрактный класс Hero, который какую-то общую для всех героев логику может содержать, повышение уровня в зависимости от количества опыта, смерть при 0 хп, ну и так далее.

Однако большая часть его методов, как вы сказали - пустые. То есть методы объявлены, но не реализованы, у них нет тела. Для темы с героем они могут быть, к примеру, такие:

public abstract int calcHandDamage();
public abstract void dance();
public abstract void castFirstSkill();
public abstract void castSecondSkill();
public abstract void castThirdSkill();
public abstract void castFourthSkill();

И так далее. Вот у нас есть абстрактный герой Hero. Знать, как отыгрывать, будут его наследники. Они реализуют заявленные абстрактными методы, каждый по-своему. Но вот в чём фишка. С самыми разными героями, хоть убийцами, хоть магами, хоть стрелками, с разными пассивками и активными скиллами, можно будет взаимодействовать одним и тем же образом – через эти методы.

Вы спросили, почему бы сразу не создать классы этих героев, зачем нам какой-то пустой Hero? Дело вот в чём. Заранее мы можем не знать, какой из героев нам понадобится. Разве разработчики Доты знают, какого персонажа каждый игрок решит пикнуть в очередной катке? Поэтому, в зависимости от пика игрока, создаётся объект нужного героя. Но чтобы в ходе игры вызывать эти все методы, нам вовсе необязательно знать, какого именно персонажа выбрал игрок. Ведь у них всех единые методы. Единая суть во многообразии форм.

Таким образом, если игрок выбрал Пуджа:

Hero selectedHero = new Pudge(); // класс Pudge наследуется от Hero

Если игрок выбрал Инвокера:

Hero selectedHero = new Invoker(); // класс Invoker тоже наследуется от Hero

А уж если решил выбрать Анти Мага:

Hero selectedHero = new AntiMage(); // не поверите, но и класс AntiMage - наследник класса Hero

Затем вам просто нужно вызывать соответствующие методы объекта, хранящегося в selectedHero. Вызван будет метод именно того объекта, который вы поместили в переменную selectedHero. Хотя она имеет тип Hero, но хранится-то там объект другого класса - класса-наследника Hero. Так что если там Пудж, то будут вызваны методы, реализованные для Пуджа. И так далее.

selectedHero.dance();
selectedHero.castFirstSkill();
int damage = selectedHero.calcHandDamage();

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