0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Закрепим пройденную теорию на одном практическом примере, показывающем типичное применение полиморфизма подтипов.</p>
1
<p>Закрепим пройденную теорию на одном практическом примере, показывающем типичное применение полиморфизма подтипов.</p>
2
<p>Представьте себе задачу расчёта стоимости туристической страховки. Это страховка, которую желательно купить при выезде за границу, на случай внезапных болезней или травм.</p>
2
<p>Представьте себе задачу расчёта стоимости туристической страховки. Это страховка, которую желательно купить при выезде за границу, на случай внезапных болезней или травм.</p>
3
<p>Сумма страховки зависит от большого числа факторов. Некоторые из факторов могут влиять на сам процесс подсчёта стоимости, то есть они изменяют не значения в формуле подсчёта, а саму формулу.</p>
3
<p>Сумма страховки зависит от большого числа факторов. Некоторые из факторов могут влиять на сам процесс подсчёта стоимости, то есть они изменяют не значения в формуле подсчёта, а саму формулу.</p>
4
<p><em>Конкретно в случае страховок, скорее всего есть одна большая формула, куда подставляются значения и вычисление происходит за один заход. Для нас сейчас главное сама концепция, а не точное знание внутренностей страхового бизнеса.</em></p>
4
<p><em>Конкретно в случае страховок, скорее всего есть одна большая формула, куда подставляются значения и вычисление происходит за один заход. Для нас сейчас главное сама концепция, а не точное знание внутренностей страхового бизнеса.</em></p>
5
<p>Если решать эту задачу в лоб, то она будет выглядеть как большое месиво вычислений со множеством условных конструкций. Со временем такой код становится крайне тяжёлым для восприятия из-за большого числа состояний, которые надо удерживать в голове.</p>
5
<p>Если решать эту задачу в лоб, то она будет выглядеть как большое месиво вычислений со множеством условных конструкций. Со временем такой код становится крайне тяжёлым для восприятия из-за большого числа состояний, которые надо удерживать в голове.</p>
6
<p>Можно ли как-то сделать код понятнее и проще для восприятия? Иногда да. Из всех факторов, участвующих в расчёте, нужно попытаться найти те, которые влияют на вычисление глобально. Они проявляются как глобальный if на верхнем уровне. Предположим, что в случае страховки это возраст. То есть считаем, что возраст определяет формулу расчёта стоимости страховки. Следующим шагом смотрим на ветки в этой условной конструкции и то, какие диапазоны там указаны. Допустим такую картину:</p>
6
<p>Можно ли как-то сделать код понятнее и проще для восприятия? Иногда да. Из всех факторов, участвующих в расчёте, нужно попытаться найти те, которые влияют на вычисление глобально. Они проявляются как глобальный if на верхнем уровне. Предположим, что в случае страховки это возраст. То есть считаем, что возраст определяет формулу расчёта стоимости страховки. Следующим шагом смотрим на ветки в этой условной конструкции и то, какие диапазоны там указаны. Допустим такую картину:</p>
7
<ul><li>До 18</li>
7
<ul><li>До 18</li>
8
<li>От 18 до 24</li>
8
<li>От 18 до 24</li>
9
<li>От 24 до 65</li>
9
<li>От 24 до 65</li>
10
<li>Старше 65</li>
10
<li>Старше 65</li>
11
</ul><p>Обратите внимание на важную деталь. Выше мы договорились, что каждая возрастная группа, определяет алгоритм расчёта стоимости страховки. То есть они между собой независимы, хотя и сам процесс вычисления местами может быть схож (и будет скорее всего).</p>
11
</ul><p>Обратите внимание на важную деталь. Выше мы договорились, что каждая возрастная группа, определяет алгоритм расчёта стоимости страховки. То есть они между собой независимы, хотя и сам процесс вычисления местами может быть схож (и будет скорее всего).</p>
12
<p>Теперь делаем переход от логической структуры к коду. Каждая возрастная группа - класс, отвечающий за вычисления стоимости для этой группы:</p>
12
<p>Теперь делаем переход от логической структуры к коду. Каждая возрастная группа - класс, отвечающий за вычисления стоимости для этой группы:</p>
13
<p>Главное, что мы получили - разделили процесс вычисления на независимые блоки кода, которые проще для восприятия. Каждый такой класс называется стратегией (вычисления). Очень важно то, что стратегия не является абстракцией, объектом с состоянием и временем жизни. Поэтому данные передаются не в конструктор, а в сам метод (вспомните курс объектно-ориентированный дизайн). По сути, это обычная функция (вычисление), которая упакована в класс только с одной целью - получить полиморфизм подтипов. Всё то же самое можно сделать (и код будет проще), используя диспетчеризацию функций по ключам.</p>
13
<p>Главное, что мы получили - разделили процесс вычисления на независимые блоки кода, которые проще для восприятия. Каждый такой класс называется стратегией (вычисления). Очень важно то, что стратегия не является абстракцией, объектом с состоянием и временем жизни. Поэтому данные передаются не в конструктор, а в сам метод (вспомните курс объектно-ориентированный дизайн). По сути, это обычная функция (вычисление), которая упакована в класс только с одной целью - получить полиморфизм подтипов. Всё то же самое можно сделать (и код будет проще), используя диспетчеризацию функций по ключам.</p>
14
<p>Дальше возникает вопрос, а каким образом и где выбрать правильную реализацию, с которой нужно работать? Вариантов здесь несколько. Выбор реализации может быть делегирован внешнему коду, то есть если мы применяем инверсию зависимостей, то работаем уже с готовой стратегией:</p>
14
<p>Дальше возникает вопрос, а каким образом и где выбрать правильную реализацию, с которой нужно работать? Вариантов здесь несколько. Выбор реализации может быть делегирован внешнему коду, то есть если мы применяем инверсию зависимостей, то работаем уже с готовой стратегией:</p>
15
<p>Пока мы только ушли от проблемы, но не решили её. В любом случае, где-то будет код, который содержит либо условную конструкцию, либо реализует один из способов диспетчеризации, которые мы разобрали в предыдущих уроках. В самом простом случае этот код будет выглядеть так:</p>
15
<p>Пока мы только ушли от проблемы, но не решили её. В любом случае, где-то будет код, который содержит либо условную конструкцию, либо реализует один из способов диспетчеризации, которые мы разобрали в предыдущих уроках. В самом простом случае этот код будет выглядеть так:</p>
16
<p>Как видно по примерам выше, кода с использованием стратегии будет больше (но не так много если используется диспетчеризация функций по ключам в ассоциативном массиве). Это касается фактически всех ситуаций, в которых задействован полиморфизм подтипов в PHP. Это цена, которую придётся заплатить за разделение, упрощающее расширение кода и уменьшающее его сложность. С другой стороны, очень легко попасть в ловушку и, наоборот, сделать сложность кода выше, чем оно было до внедрения полиморфизма подтипов. Этот полиморфизм делает код многословным и излишне абстрактным, если применять его налево и направо. А расширение нужно не так часто, как об этом говорят. Более того, инвертировать зависимости можно по ходу действия, когда в этом появляется необходимость.</p>
16
<p>Как видно по примерам выше, кода с использованием стратегии будет больше (но не так много если используется диспетчеризация функций по ключам в ассоциативном массиве). Это касается фактически всех ситуаций, в которых задействован полиморфизм подтипов в PHP. Это цена, которую придётся заплатить за разделение, упрощающее расширение кода и уменьшающее его сложность. С другой стороны, очень легко попасть в ловушку и, наоборот, сделать сложность кода выше, чем оно было до внедрения полиморфизма подтипов. Этот полиморфизм делает код многословным и излишне абстрактным, если применять его налево и направо. А расширение нужно не так часто, как об этом говорят. Более того, инвертировать зависимости можно по ходу действия, когда в этом появляется необходимость.</p>