Skip to content

Отношения Strategy с другими паттернами

Мост, стратегия и состояние (а также отчасти и адаптер) имеют схожие структуры классов — все они построены на принципе «композиции», то есть делегируют работу другим объектам. Различаются они тем, что решают разные проблемы. Помните, что паттерны — это не только рецепт построения кода определённым образом, но и описание проблем, которые привели к данному решению.

Команда и стратегия похожи по духу, но различаются масштабом и применением:

Команду используют, чтобы превратить любые разнородные действия в объекты. Параметры операции превращаются в поля объекта. Этот объект теперь можно логировать, хранить в истории для отмены, передавать во внешние сервисы и так далее.

Стратегия же описывает разные способы произвести одно и то же действие, позволяя взаимно заменять эти способы в каком-то объекте контекста.

Стратегия меняет поведение объекта «изнутри», а декоратор изменяет его «снаружи».

Шаблонный метод использует наследование, чтобы расширять части алгоритма. Стратегия использует делегирование, чтобы изменять выполняемые алгоритмы на лету. Шаблонный метод работает на уровне классов. Стратегия позволяет менять логику отдельных объектов.

Состояние можно рассматривать как надстройку над стратегией. Оба паттерна используют композицию, чтобы менять поведение основного объекта, делегируя работу вложенным объектам-помощникам. Однако в стратегии эти объекты не знают друг о друге и никак не связаны друг с другом. А в паттерне состояние сами конкретные состояния могут переключать контекст.

Концептуальный пример

Представь, что ты разрабатываешь «In-Memory-Cache». Поскольку он находится внутри памяти, его размер ограничен. Как только In-memory-cache полностью заполнится, какие-то записи придется убрать для освобождения места. Эту функцию можно реализовать с помощью нескольких алгоритмов. Вот самые популярные среди них:

— Наиболее давно использовавшиеся (Least Recently Used – LRU): убирает запись, которая использовалась наиболее давно.

— Первым пришел, первым ушел (First In, First Out — FIFO): убирает запись, которая была создана раньше остальных.

— Наименее часто использовавшиеся (Least Frequently Used — LFU): убирает запись, которая использовалась наименее часто.

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

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

Теперь основной класс нашего кеша будет включать в себя evictionAlgo. Вместо прямой реализации всех типов алгоритмов вытеснения внутри самого себя наш класс будет передавать их в evictionAlgo. Поскольку это интерфейс, мы можем непосредственно во время выполнения программы менять алгоритм на LRU, FIFO, LFU без изменений в классе кеша.

evictionAlgo.go: интерфейс стратегии

fifo.go: конкретная стратегия

lru.go: конкретная стратегия

lfu.go: конкретная стратегия

cache.go: контекст

main.go: клиентский код

Пришло время поработать с кодом!

output.txt: результат выполнения

С оригиналом статьи ты можешь ознакомиться по ссылке (может потребоваться VPN).