Використання схеми стратегії та команди команд


121

Обидві структури дизайну інкапсулюють алгоритм та відокремлюють деталі реалізації від своїх класів викликів. Єдина відмінність, яку я можу помітити, полягає в тому, що шаблон стратегії приймає параметри для виконання, в той час як шаблон команди - ні.

Мені здається, що шаблон команди вимагає, щоб вся інформація для виконання була доступною при його створенні, і він може затримати його виклик (можливо, як частина скрипту).

Які визначення визначають, чи слід використовувати один чи інший візерунок?

Відповіді:


94

Я включаю таблицю ієрархії інкапсуляції кількох моделей проектування GoF, щоб допомогти пояснити відмінності між цими двома моделями. Сподіваємось, це краще ілюструє, що кожна інкапсуляція, тому моє пояснення має більше сенсу.

По-перше, ієрархія перераховує сферу, для якої застосовується даний шаблон, або відповідний зразок, який слід використовувати для інкапсуляції певного рівня деталізації, залежно від того, з якої сторони таблиці ви починаєте.

таблиця ієрархії табл

Як видно з таблиці, об’єкт "Шаблон стратегії" приховує деталі реалізації алгоритму, тому використання іншого об'єкта стратегії буде виконувати ту ж функціональність, але по-іншому. Кожен об'єкт стратегії може бути оптимізований під певний фактор або працювати з іншим параметром; і, використовуючи загальний інтерфейс, контекст може безпечно працювати з будь-яким.

Шаблон команди включає в себе значно менший рівень деталізації, ніж алгоритм. Він кодує реквізити, необхідні для надсилання повідомлення об’єкту: приймач, селектор та аргументи. Перевага об'єктивації такої крихітної частини виконання процесу полягає в тому, що такі повідомлення можна викликати в різні моменти часу або місця загальним способом без необхідності жорсткого кодування його деталей. Це дозволяє виклику повідомлень один або більше разів або передавати їх до різних частин системи або декількох систем, не вимагаючи, щоб деталі конкретного виклику були відомі перед виконанням.

Як це характерно для моделей дизайну, вони не вимагають, щоб усі реалізації були детально ідентичними, щоб носити назву шаблону. Деталі можуть відрізнятися в реалізації та в тому, які дані кодуються в об'єкті, як аргументи методу.


Тож якби у мене була система, яка фільтрувала результати за допомогою «трубопроводу фільтру» і використовувала делегати як фільтри (де кожен алгоритм фільтра буде інкапсульований у межах функції), чи вважали б це командним шаблоном? У цьому випадку я бачу делегата функції фільтра як надання контракту на зразок того, чого повинен дотримуватися кожен фільтр з точки зору введення та виведення.
KTF

4
@KTF, ні. У шаблоні Command використовується об'єкт, який має більшість (якщо не всю) інформації, необхідної (наприклад, приймач, селектор, аргументи) для виклику методу об'єкта. Це спрощений візерунок, який можна використовувати в інших моделях дизайну, таких як Ланцюг відповідальності, колекція та шаблон трубопроводу, який ви описуєте. "Різний договір", наданий вашими делегатами, - це ще одна модель, інтерфейс.
Хупернікетес

50

Стратегії інкапсулюють алгоритми. Команди відокремлюють відправника від одержувача запиту, вони перетворюють запит у об’єкт.

Якщо це алгоритм, як щось буде зроблено, використовуйте Стратегію. Якщо вам потрібно відокремити виклик методу від його виконання, використовуйте команду Command. Команди часто використовуються під час черги повідомлень для подальшого використання, наприклад, завдання або транзакції.


що має сенс en.wikipedia.org/wiki/Command_Pattern, клієнт та інкасатор пов'язані, але в той же час вони не знають один про одного!
Калпеш Соні

26

Відповідаючи на дуже давнє запитання. (хтось бачить останні відповіді замість більшості голосів?)

Це дійсна плутанина через подібність. І схеми стратегії, і командування використовують інкапсуляцію . Але це не робить їх однаковими.

Ключова відмінність полягає в розумінні того, що інкапсульовано. Принцип ОО, від якого залежать обидва шаблони, полягає в інкапсуляції того, що змінюється .

Що стосується стратегії, то різниться алгоритм . Наприклад, один об’єкт стратегії знає, як вивести файл XML, а інший виводить, скажімо, в JSON. У різних класах зберігаються ( інкапсульовані ) різні алгоритми . Це так просто.

У випадку команди, що змінюється, - це сам запит . Запит може надходити від File Menu > Deleteабо Right Click > Context Menu > Deleteабо Just Delete Button pressed. Усі три випадки можуть генерувати 3 командні об'єкти одного типу. Ці командні об'єкти представляють лише 3 запити на видалення; не алгоритм видалення. Оскільки запити зараз є безліччю об’єктів, ми могли легко ними керувати. Раптом стає тривіально надати такі функції, як скасувати чи повторити.

Не має значення, як команда реалізує запитувану логіку. При виклику Execute () він може реалізувати алгоритм для запуску видалення або навіть делегувати його іншим об'єктам, навіть делегувати стратегію. Це лише деталізація реалізації командного шаблону. Ось чому його називають командою, хоча це не ввічливий спосіб запитувати : -)

Протиставляйте це стратегії; ця закономірність стосується лише фактичної логіки, яка виконується. Якщо ми це зробимо, це допоможе досягти різних комбінацій поведінки з мінімальним набором класів, тим самим запобігаючи вибуху класу.

Я думаю, що Command допомагає нам розширити розуміння інкапсуляції, тоді як Стратегія забезпечує природне використання інкапсуляції та поліморфізму.


15

Я дивлюся на те, що у вас є кілька способів зробити одне і те ж, кожен з них - це стратегія, і щось під час виконання визначає, яку стратегію виконувати.

Можливо, спершу спробуйте StrategyOne, якщо результати недостатньо хороші, спробуйте StrategyTwo ...

Команди зобов'язані відрізнятись від речей, які повинні відбутися, як TryToWalkAcrossTheRoomCommand. Ця команда буде запущена щоразу, коли якийсь об’єкт повинен спробувати пройти по кімнаті, але всередині нього, він може спробувати StrategyOne та StrategyTwo для спроби пройти по кімнаті.

Позначити


2
RE: "декілька способів зробити те саме" - Це, здається, суперечить деяким загальним прикладам Стратегії. Зокрема ті, де є класи реалізації, які роблять додавання, віднімання, множення тощо. Можливо, це не гарні приклади?
Джошуа Девіс

1
@JoshuaDavis всі ці «підстратегії» - це особливі випадки однієї стратегії: арифметична операція . вони мають загальні аргументи (2 операнди) і в результаті отримують одне значення. багато чого роблять те саме (будучи чорношкірими) річчю по-різному, залежно від реалізації. тож я не бачу тут жодного конфлікту, але, навпаки: приємний приклад =)
jungle_mole

7

Я можу помилитися на свою думку, але я трактую команду як функцію для виконання або реакцію. Повинно бути не менше двох гравців: той, хто вимагає дії, і той, хто виконує дію. GUI є типовим прикладом для шаблону команд:

  • Усі кнопки на панелі інструментів програми пов'язані з деякою дією.
  • Кнопка є виконавцем у цій справі.
  • Дія - це команда в цьому випадку.

Команда, як правило, обмежена певною сферою чи діловою сферою, але це не обов'язково: у вас можуть бути команди, які видають рахунок, запускають ракету або видаляють файл, що реалізує той самий інтерфейс (наприклад, один execute()метод) в межах однієї програми. Часто команди є самостійними, тому їм не потрібно нічого від виконавця, щоб обробити завдання, яке вони мають намір (вся необхідна інформація надається під час побудови), іноді команди залежать від контексту і повинні бути в змозі виявити цей контекст ( Команда Backspace повинна знати положення каретки в тексті, щоб правильно видалити попередній символ; Відкат команда повинна відкрити поточну транзакцію для відкату, ...).

Стратегія трохи відрізняється: він більш прив'язаний до якої - то області. Стратегія може визначати правило для форматування дати (у UTC - специфічній для місцевості?) (Стратегії "форматера дати") або для обчислення квадрата для геометричної фігури (стратегія "квадратний калькулятор"). У цьому сенсі стратегії - це полегшені об'єкти, які беруть щось як вихідний ("дата", "цифра", ...) і приймають на його основі якесь рішення. Може бути , не найкращий, але хороший приклад стратегії є один пов'язаний з javax.xml.transform.Sourceінтерфейсом: в залежності від того , чи є переданий об'єкт DOMSourceабо SAXSourceабо StreamSourceстратегія (= XSLT трансформатор в даному випадку) буде застосовувати різні правила для його обробки. Впровадження може бути простим switchабо включати схему відповідальності .

Але дійсно є щось спільне між цими двома шаблонами: команди та стратегії інкапсулюють алгоритми в межах однієї смислової області.


1
Я трактую команду як функцію зворотного виклику або як реакцію. Повинні бути принаймні два гравці: той, хто вимагає дії, і той, хто виконує ... - Я розумію, що ви намагаєтесь сказати, але я б ухилявся від використання слова "зворотний виклик", тому що часто це слово "зворотний виклик" означає асинхронний виклик, і вам не потрібно робити асинхронні виклики, щоб шаблон команди був корисним. Справа в суті: Microsoft Word. Клацання кнопки на панелі інструментів та натискання клавіш швидкого доступу не викликають асинхронних команд, але ми можемо оцінити, як командний шаблон буде корисний у цьому випадку
Джим Г.

Я згоден, хоча, як сказав Джим, я редагую, щоб видалити посилання на зворотний дзвінок.
JARC

Дякую, я зробив кілька розширень. Повідомте мене, якщо ви згодні / не згодні.
dma_k

5

Команда:

Основні компоненти:

  1. Команда оголошує інтерфейс для абстрактних команд типуexecute()
  2. Одержувач знає, як виконати певну команду
  3. Invoker тримає ConcreteCommand , який повинен бути виконаний
  4. Клієнт створює ConcreteCommand та призначає Приймач
  5. ConcreteCommand визначає зв'язок між командою та приймачем

Робочий процес:

Клієнт викликає Invoker => Invoker викликає ConcreteCommand => ConcreteCommand викликає метод Receiver , який реалізує абстрактний метод Command .

Перевага : На клієнта не впливають зміни в команді та приймачі. Invoker забезпечує слабке з'єднання між Клієнтом та Одержувачем. Ви можете запустити кілька команд одним і тим же Invoker.

Шаблон команд дозволяє виконати команду на різних приймачах за допомогою одного і того ж Invoker . Invoker не знає тип приймача

Для кращого розуміння концепцій, поглянути на цю JournalDev статтю по Pankaj Kumar і DZone статті по Джеймс Sugrue на додаток до Вікіпедії посилання.

Ви можете використовувати шаблон команди для

  1. Від’єднайте виклик і приймач команд

  2. Впровадити механізм зворотного виклику

  3. Реалізуйте функцію скасування та повторення

  4. Ведіть історію команд

java.lang.Thread- це одна гарна реалізація схеми Command . Ви можете розглядати Thread як виклик і клас, що реалізує Runnable як ConcreteCommonad / Receiver, а run()метод як Command .

Скасувати / скасувати версію шаблону команд можна прочитати у статті Теодора Норвелла

Стратегія:

Шаблон стратегії зрозумілий дуже просто. Використовуйте цю схему, коли

У вас є кілька реалізацій алгоритму, і реалізація алгоритму може змінюватися під час виконання, залежно від конкретних умов .

Візьмемо приклад компонента Fare системи бронювання авіакомпаній

Авіакомпанії хочуть запропонувати різні тарифи протягом різних періодів часу - пік і пік місяців. У дні пік-подорожі в пік, він хоче стимулювати попит, пропонуючи привабливі знижки.

Основні заходи стратегії :

  1. Це поведінковий зразок
  2. Він заснований на делегуванні
  3. Він змінює кишки об'єкта, змінюючи поведінку методу
  4. Він використовується для перемикання між сімейством алгоритмів
  5. Це змінює поведінку об'єкта під час виконання

Пов’язані публікації з прикладами коду:

Використовуючи шаблон дизайну команд

Приклад реального світу стратегії


0

Для мене різниця - одна з намірів. Реалізація обох шаблонів досить схожа, але має різні цілі:

  • Для стратегії компонент, що використовує об'єкт, знає, що робить об'єкт (і використовуватиме його для виконання частини власної роботи), але йому не важливо, як це робити.

  • Для Command компонент, що використовує об'єкт, не знає ні того, що робить Command, ні як це робить - він просто знає, як викликати його. Завдання абонента - просто запустити команду - обробка, здійснена командою, не є частиною основної роботи абонента.

У цьому різниця - чи об'єкт, що використовує компонент, насправді знає чи дбає про те, що робить компонент? Більшу частину часу це можна визначити, виходячи з того, чи повертає об'єкт шаблону значення своєму виклику. Якщо виклик піклується про те, що робить об’єкт шаблону, він, ймовірно, захоче щось повернути, і це буде Стратегія. Якщо це не турбується про якесь повернене значення, це, мабуть, команда (зауважте, щось на зразок Java Callable все ще є командою, оскільки, хоча воно повертає значення, абонент не піклується про значення - він просто передає його назад до того, що спочатку подавали Команду).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.