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