# Упущенные возможности полиморфизма

(В оригинале - Missing Opportunities for Polymorphism)

Полиморфизм – одна из фундаментальных идей объектно-ориентированного подхода. Перевод этого слова с греческого – «множество форм». В контексте программирования речь идет о множестве форм конкретного класса, объекта или метода. Но полиморфизм – это не только альтернативные реализации. Будучи правильно использованным, полиморфизм позволяет обходиться без конструкций if-then-else. Нахождение внутри контекста позволяет нам выполнить нужный код непосредственно, тогда как нахождение вне контекста вынуждает переделать код так, чтобы сделать это правильно. Аккуратно используя альтернативные реализации, мы сможем сделать код более компактным, а значит, более сопровождаемым. Лучше всего это продемонстрировать на примере, скажем, упрощенной корзины покупок:

```
public class ShoppingCart {
    private ArrayList<Item> cart = new ArrayList<Item>();
    public void add(Item item) { cart.add(item); }
    public Item takeNext() { return cart.remove(0);  }
    public boolean isEmpty() { return cart.isEmpty(); }
}
```

Пусть наш интернет-магазин предлагает два вида товаров – которые можно скачать, и которые надо посылать почтой. Создадим объект, который поддерживает следующие операции:

```
public class Shipping {
    public boolean ship(Item item, SurfaceAddress address) { ... }
    public boolean ship(Item item, EMailAddress address { ... }
}
```

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

```
while (!cart.isEmpty()) {
    shipping.ship(cart.takeNext(), ???);
}
```

«???» здесь вовсе не какой-то новый супероператор, а всего лишь вопрос, ответ на который указывает, надо ли послать этот товар по электронной почте или же по обычной. Однако контекст, необходимый для ответа на этот вопрос, уже не существует. Мы могли бы использовать флаг или enum для этого и применить конструкцию if-then-else. Другое же решение – создать два класса, расширяющих функциональность класса item. Назовем их для примера DownloadableItem и SurfaceItem. Теперь напишем код. Сделаем Item интерфейсом с единственным методом ship. Чтобы выполнить доставку, нужно будет вызвать item.ship(). Реализация метода ship будет в классах DownloadableItem и SurfaceItem.

```
public class DownloadableItem implements Item {
    public boolean ship(Shipping shipper) {
        shipper.ship(this, customer.getEmailAddress());
    }
}

public class SurfaceItem implements Item {
    public boolean ship(Shipping shipper) {
        shipper.ship(this, customer.getSurfaceAddress());
    }
}
```

В этом примере мы делегировали ответственность за правильную доставку объекту Item. Поскольку каждый объект Item знает как его нужно доставить, это позволяет нам обойтись без конструкции if-then-else. Данный код также демонстрирует использование двух паттернов проектирования, часто работающих в паре: Command и Double Dispatch. Эффективное использование этих паттернов основано на правильном использовании полиморфизма. Такое использование приведет к уменьшению количества конструкций if-then-else в коде.

И хотя бывают случаи, когда использование if-then-else оправдано более, чем применение полиморфизма, чаще всего полиморфизм дает в результате более компактный и более ясный для понимания код. Количество упущенных возможностей – это просто количество конструкций if-then-else в вашем коде.

Автор оригинала - [Kirk Pepperdine](http://programmer.97things.oreilly.com/wiki/index.php/Kirk_Pepperdine)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://97-things-every-x-should-know.gitbook.io/97-things-every-programmer-should-know/ru/thing_88.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
