> For the complete documentation index, see [llms.txt](https://evgenii-afanasev.gitbook.io/ruby-course/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://evgenii-afanasev.gitbook.io/ruby-course/3_oop/4_polymorphism.md).

# Полиморфизм (Duck typing)

## Полиморфизм

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

```ruby
class Duck
  def voice
    puts "Hi, I'm a Duck"
  end
end
```

```ruby
class  Goose < Duck
  def voice
    puts "Hi, I'm a Goose"
  end
end
```

```ruby

# Мы ожидаем, что в аргументы метода будет передан какой-то объект у которого мы вызовем метод
def animal_voice(animal)
  #  метод voice является общим признаком и для Duck и для Goose
  animal.voice
end

duck = Duck.new
goose = Goose.new

animal_voice(duck) # = Hi, I'm a Duck
animal_voice(goose) # = Hi, I'm a Goose
```

Возможно может показаться, что это сработало благодаря наследованию, но на самом деле наследование здесь никакой роли не играет. И тот и другой класс имеют метод с одинаковым названием `voice`. Метод `animal_voice` не имеет никакой информации какой объект будет ему передан. Мы лишь знаем, что у этого объекта должен быть метод `voice`. Если вы уберете наследование и попробуете запустить код, то **ничего не поменяется**.

## Duck typing

Почему это называют duck typing ? Дословно это переводится как "Утиная типизация", которая гласит: если объект выглядит как утка и может делать тоже самое, что и утка, значит мы можем быть уверены, что это утка. На самом деле с самой уткой тут ничего общего нет, поэтому вместо слово утки можете подставить любое название.

## Итоги

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

И еще раз, полиморфизмом не является то, что мы можем у аргумента метода вызывать метод с одинаковым назывнием. Полиморфизм это возвожность работать с объектами разных классов **по общему признаку**.

## Задание animals

**Внимание ! Это и последующие задания данного модуля с названием `animals` необходимо выполнять в одной и той же директории в корне модуля - `3_oop/animals`**

* перенесите вашу логику перекормления до смерти и замяукивания до смерти в отдельные методы, `def meow_until_death(animal)` и `def eat_until_death(animal)` соответственно, которые будут принимать объект кота в аргументах.
* вызовите эти методы для разных котов
* Создайте несколько экземпляров класса `Dog`. Попробуйте применить ваши методы на объектах класса собаки.
* Убедитесь, что метод работает исправно для собаки и для кота
* Какое поведение вы наблюдаете ?

## Задание company

**Внимание ! Это и последующие задания данного модуля с названием `company` необходимо выполнять в одной и той же директории в корне модуля - `3_oop/company`**

* Создайте класс компании `Company`, содержащей сотрудников и реализующей методы:
  * `hire(employee)` - найм одного сотрудника. В аргументах метод ожидает получить объект на базе класса сотрудника.
  * `hireAll(employes)` - найм списка сотрудников. В аргументах метод ожидает получить массив объектов на базе классов сотрудника.
  * `fire(employee)` - увольнение сотрудника. В аргументах метод ожидает получить объект класса `Employee`
* Создайте классы сотрудников `Manager`, `TopManager` и `Operator` с методом получения информациии о зарплате `get_salary` и условиями начисления зарплаты:
  * `Manager` — зарплата складывается из фиксированной части и бонуса в виде 5% от заработанных для компании денег. Количество заработанных денег для компании генерируйте случайным образом от 115 000 до 140 000 рублей в момент установления заработной платы.
  * `TopManager` — зарплата складывается из фиксированной части и бонуса в виде 150% от заработной платы, если доход компании более 10 млн рублей.
  * `Operator` — зарплата складывается только из фиксированной части.

Рекомендации:

* Чтобы получить данные компании внутри класса сотрудника, настройте хранение ссылки на Company и передавайте объект Company с помощью конструктора.
* Сделайте возможным создание разных экземпляров компании со своим списком сотрудников и доходов.
* Данное задание творческое. Многие ньюансы и подробности были специально опущены, чтобы вы могли сами придумать как та или иная функциональность будет работать.

## Дополнительный материал

* [Полиморфизм](https://blog.appsignal.com/2022/05/25/an-introduction-to-polymorphism-in-ruby-on-rails.html)
* [Duck typing](https://chetan.medium.com/duck-typing-in-ruby-212a25b90cec)
