Я знаю, что это старый вопрос, но я думаю, что у меня есть еще один интересный пример, который я недавно реализовал.
Это очень практичный пример использования стратегии в системе доставки документов.
У меня была система доставки PDF, которая получила архив, содержащий много документов и некоторые метаданные. На основе метаданных было решено, куда поместить документ; скажем, в зависимости от данных, я мог бы хранить документ в A
, B
или C
системах хранения, или в комбинации из трех.
Различные клиенты использовали эту систему, и у них были разные требования к откату / обработке ошибок в случае ошибок: один хотел, чтобы система доставки остановилась при первой ошибке, оставила все документы уже доставленными в свои хранилища, но остановила процесс, а не доставить что-нибудь еще; другой хотел откатить с B
в случае ошибок при сохранении в C
, но оставить все, что уже было доставлено на A
. Легко представить, что у третьего или четвертого тоже будут разные потребности.
Чтобы решить эту проблему, я создал базовый класс доставки, который содержит логику доставки, а также методы для отката вещей из всех хранилищ. Эти методы фактически не вызываются системой доставки напрямую в случае ошибок. Вместо этого класс использует Dependency Injection для получения класса «Стратегия отката / обработки ошибок» (на основе клиента, использующего систему), который вызывается в случае ошибок, который, в свою очередь, вызывает методы отката, если это подходит для этой стратегии.
Сам класс доставки сообщает, что происходит с классом стратегии (какие документы были доставлены, какие хранилища и какие сбои произошли), и всякий раз, когда возникает ошибка, он спрашивает стратегию, продолжать или нет. Если в стратегии написано «остановите это», класс вызывает метод «cleanUp» стратегии, который использует ранее сообщенную информацию, чтобы решить, какие методы отката следует вызвать из класса доставки, или просто ничего не делать.
rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);
if (rollbackStrategy.mustAbort()) {
rollbackStrategy.rollback(); // rollback whatever is needed based on reports
return false;
}
Итак, теперь у меня есть две разные стратегии: одна - это QuitterStrategy
(которая завершается при первой ошибке и ничего не очищает), а другая - MaximizeDeliveryToAStrategy
(которая старается изо всех сил не прерывать процесс и никогда не откатывать вещи, доставленные в хранилище A
, но откатывает вещи с B
, если доставка до C
не удалась).
Насколько я понимаю, это один из примеров стратегии. Если вы (да, вы читаете) думаете, что я неправ, пожалуйста, прокомментируйте ниже и дайте мне знать. Мне любопытно, что представляет собой «чистое» использование шаблона стратегии и какие аспекты моей реализации нарушают это определение. Я думаю, это выглядит немного смешно, потому что интерфейс стратегии немного толстый. Все примеры, которые я видел до сих пор, используют только один метод, но я все еще думаю, что он инкапсулирует алгоритм (если часть бизнес-логики можно считать алгоритмом, который, я думаю, делает).
Поскольку стратегия также уведомляется о событиях во время выполнения доставки, ее также можно считать Наблюдателем , но это уже другая история.
После небольшого исследования кажется, что это «составной шаблон» (например, MVC, шаблон, который использует несколько шаблонов проектирования под определенным образом), называемый Advisor . Это советник о том, должна ли доставка продолжаться или нет, но он также является активным обработчиком ошибок, так как он может откатывать вещи по запросу.
В любом случае, это довольно сложный пример, который может создать у вас ощущение, что использование шаблона стратегии слишком просто / глупо. Он может быть действительно сложным и даже более применимым при использовании вместе с другими шаблонами.