Содержание
Клиент должен создать объект конкретной стратегии и передать его в конструктор контекста. Кроме этого, клиент должен иметь возможность заменить стратегию на лету, используя сеттер. Благодаря этому, контекст не будет знать о том, какая именно стратегия сейчас выбрана.
Во время выполнения программы контекст получает вызовы от клиента и делегирует их объекту конкретной стратегии. Хотя каждый класс будет прокладывать маршрут по-своему, для навигатора это не будет иметь никакого значения, так как его работа заключается только в отрисовке маршрута. Навигатору достаточно подать в стратегию данные о начале и конце маршрута, чтобы получить массив точек маршрута в оговорённом формате.
Система, построенная на основе наследования, является статичной. Заменить один алгоритм на другой в ходе выполнения программы уже невозможно. С другой стороны, Стратегия описывает разные способы произвести одно и то же действие, позволяя взаимозаменять эти способы в каком-то объекте контекста. Изолирует код и данные алгоритмов от остальных классов. Клиенты контекста должны подавать в него соответствующий объект-стратегию, когда хотят, чтобы контекст вёл себя определённым образом. Конкретные стратегии реализуют различные вариации алгоритма.
Шаблонный метод использует наследование, чтобы расширять части алгоритма. Стратегия использует делегирование, чтобы изменять выполняемые алгоритмы на лету. Стратегия позволяет менять логику отдельных объектов. Стратегия помещает каждую лапу такого оператора в отдельный класс-стратегию.
Вместо того, чтобы изначальный класс сам выполнял тот или иной алгоритм, он будет играть роль контекста, ссылаясь на одну из стратегий и делегируя ей выполнение работы. Чтобы сменить алгоритм, вам будет достаточно подставить в контекст другой объект-стратегию. Когда различные вариации алгоритмов реализованы в виде развесистого условного оператора. Каждая ветка такого оператора представляет собой вариацию алгоритма.
Результаты применения паттерна Strategy
В нашем примере каждый алгоритм поиска пути переедет в свой собственный класс. В этих классах будет определён лишь один метод, принимающий в параметрах координаты начала и конца пути, а возвращающий массив точек маршрута. Реализацию на PHP приводить не буду, так как она довольно простая, если понять суть применения паттерна на практике. Проблему может вызвать только необходимость иметь что-то вроде фабрики или фабричного метода для создания нужной реализации конкретного поведения объекта. Но это можно легко сделать при помощи механизма внедрения зависимостей , без которого не обходится ни один проект. Стратегия позволяет вынести отличающееся поведение в отдельную иерархию классов, а затем свести первоначальные классы к одному, сделав поведение этого класса настраиваемым.
Стратегия определяет интерфейс, общий для всех вариаций алгоритма. Контекст использует этот интерфейс для вызова алгоритма. Можно доехать на автобусе, такси или велосипеде. Вы выбираете конкретную стратегию в зависимости от контекста — наличия денег или времени до отлёта.
Сделать это можно на этапе создания объекта, просто передав в конструктор требуемый экземпляр реализации поведения. Паттерн Стратегия представляет шаблон проектирования, который определяет набор алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость. В зависимости от ситуации мы можем легко заменить один используемый алгоритм другим. При этом замена алгоритма происходит независимо от объекта, который использует данный алгоритм. Состояние можно рассматривать как надстройку над Стратегией. Оба паттерна используют композицию, чтобы менять поведение основного объекта, делегируя работу вложенным объектам-помощникам.
Зачем нужен паттерн «Стратегия»
Для контекста неважно, какая именно вариация алгоритма будет выбрана, так как все они имеют одинаковый интерфейс. Возможно, стоит вернуться к этому материалу позже. Все это, конечно, хорошо, но зачем все это нужно? Ведь такая реализация приводит к тому, что мы усложняем статический анализ кода, пряча конкретную реализацию поведения за интерфейсом и используемым механизмом внедрения зависимостей. Паттерн Strategy позволяет скрыть детали реализации алгоритмов от клиента.
- Для правильной настройки системы пользователь должен знать об особенностях всех алгоритмов.
- Однако в Стратегии эти объекты не знают друг о друге и никак не связаны.
- Шаблонный метод использует наследование, чтобы расширять части алгоритма.
- При этом замена алгоритма происходит независимо от объекта, который использует данный алгоритм.
- Ведь такая реализация приводит к тому, что мы усложняем статический анализ кода, пряча конкретную реализацию поведения за интерфейсом и используемым механизмом внедрения зависимостей.
- Затем контекст получает определённый объект-стратегию от клиента и делегирует ему работу.
Затем контекст получает определённый объект-стратегию от клиента и делегирует ему работу. Если вдруг понадобится сменить алгоритм, в контекст можно подать другую стратегию. Стратегия позволяет изолировать код, данные и зависимости алгоритмов от других объектов, скрыв эти детали внутри классов-стратегий. Стратегия позволяет варьировать поведение объекта во время выполнения программы, подставляя в него различные объекты-поведения (например, отличающиеся балансом скорости и потребления ресурсов). Контекст хранит ссылку на объект конкретной стратегии, работая с ним через общий интерфейс стратегий.
В этом примере контекст использует Стратегию для выполнения той или иной арифметической операции. Если есть поведение, то должен быть интерфейс, его реализация, и эта реализация должна внедряться как зависимость. Нужно идти от простого к сложному, всегда оставляя место для шага вперед. Если перекрывать в наследнике реализацию поведенческого метода родителя.
Обычного наследования недостаточно: зачем использовать паттерн «Стратегия» в разработке
Мост, Стратегия и Состояние (а также слегка и Адаптер) имеют схожие структуры классов — все они построены на принципе «композиции», то есть делегирования работы другим объектам. Тем не менее, они отличаются тем, что решают разные проблемы. Помните, что паттерны — это не только рецепт построения кода определённым образом, но и описание проблем, которые привели к данному решению. Паттерн Strategy переносит в отдельную иерархию классов все детали, связанные с реализацией алгоритмов. Для случая программы сжатия файлов абстрактный базовый класс Compression этой иерархии объявляет интерфейс, общий для всех алгоритмов и используемый классом Compressor.
Создайте интерфейс стратегий, описывающий этот алгоритм. Он должен быть общим для всех вариантов алгоритма. Одной из самых востребованных функций являлся поиск и прокладывание маршрутов. Пребывая в неизвестном ему городе, пользователь должен иметь возможность указать начальную точку и пункт назначения, а навигатор — проложит оптимальный путь.
https://goforex.info/ следующим шагом вы добавили в навигатор прокладывание пеших маршрутов. Поведение объекта делегируется другому объекту, который реализует это поведение. В итоге делегат реализует поведение и является зависимостью для объекта, поведение которого он реализует.
Класс Context хранит ссылку на объект IStrategy и связан с интерфейсом IStrategy отношением агрегации. Когда у вас есть множество похожих классов, отличающихся только некоторым поведением. В ближайшей перспективе вы хотели бы добавить прокладывание маршрутов по велодорожкам. А в отдалённом будущем — интересные маршруты посещения достопримечательностей. Реализация паттерна «Стратегия» лишена этого недостатка.
Подклассы ZIP_Compression, ARJ_Compression и RAR_Compression его реализуют в соответствии с тем или иным алгоритмом. Класс Compressor содержит указатель на объект абстрактного типа Compression и предназначен для переадресации пользовательских запросов конкретному алгоритму. Для замены одного алгоритма другим достаточно перенастроить этот указатель на объект нужного типа. Важно, чтобы все стратегии имели общий интерфейс. Используя этот интерфейс, контекст будет независимым от конкретных классов стратегий. С другой стороны, вы сможете изменять и добавлять новые виды алгоритмов, не трогая код контекста.
Назначение паттерна Strategy
Систему проще поддерживать и модифицировать, так как семейство алгоритмов перенесено в отдельную иерархию классов. Классы ConcreteStrategy1 и ConcreteStrategy, которые реализуют интерфейс IStrategy, предоставляя свою версию метода Algorithm(). Подобных классов-реализаций может быть множество. Стратегия меняет поведение объекта «изнутри», а Декоратор изменяет его «снаружи». Команду используют, чтобы превратить любые разнородные действия в объекты. Этот объект теперь можно логировать, хранить в истории для отмены, передавать во внешние сервисы и так далее.
Однако в Стратегии эти объекты не знают друг о друге и никак не связаны. В Состоянии сами конкретные состояния могут переключать контекст. Начать можно с обычного делегирования, чтобы отделить поведение от данных и вынести реализацию поведения в отдельный объект. Если в будущем появится необходимость реализации нескольких вариантов поведения, можно реализовать интерфейс для поведения и перейти к паттерну «Стратегия».
Любое изменение алгоритмов поиска, будь то исправление багов или добавление нового алгоритма, затрагивало основной класс. Это повышало риск сделать ошибку, случайно задев остальной работающий код. Если с популярностью навигатора не было никаких проблем, то техническая часть вызывала вопросы и периодическую головную боль. С каждым новым алгоритмом код основного класса навигатора увеличивался вдвое. В таком большом классе стало довольно трудно ориентироваться. Первая версия вашего навигатора могла прокладывать маршрут лишь по дорогам, поэтому отлично подходила для путешествий на автомобиле.