Я знаю, що це старе запитання, але, думаю, у мене є ще один цікавий приклад, який я впровадив нещодавно.
Це дуже практичний приклад шаблону стратегії, який використовується в системі доставки документів.
У мене була система доставки 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
доставки доC
не вдається).
Наскільки я розумію, це один із прикладів стратегії. Якщо ви (так, читаєте) вважаєте, що я помиляюся, будь ласка, коментуйте нижче та повідомте мене. Мені цікаво, що може означати "чисте" використання шаблону стратегії, і які аспекти моєї реалізації порушують це визначення. Я думаю, це виглядає трохи смішно, тому що стратегічний інтерфейс трохи жирний. У всіх прикладах, які я бачив до цього часу, використовується лише один метод, але я все ще думаю, що це інкапсулює алгоритм (якщо частину бізнес-логіки можна вважати алгоритмом, що, на мою думку, є).
Оскільки стратегія також повідомляється про події під час виконання доставки, її також можна вважати спостерігачем , але це вже інша історія.
З невеликого дослідження, здається, що це "складений шаблон" (наприклад, MVC, шаблон, який використовує декілька шаблонів дизайну внизу певним чином), який називається Advisor . Це радник щодо продовження доставки чи ні, але це також активний обробник помилок, оскільки він може відмовляти речі, коли про це просять.
У будь-якому випадку, це досить складний приклад, який може викликати у вас відчуття, що звичаї стратегії є надто простими / безглуздими. Він може бути справді складним і навіть більш застосовним, якщо його використовувати разом з іншими візерунками.