Шаблон проектирования команд является одним из широко известных шаблонов проектирования, и он подпадает под модель «Поведенческий дизайн» (часть «Банды четырех»). Как следует из названия, это связано с действиями и событиями в приложении.
Постановка задачи:
Представьте себе сценарий, в котором у нас есть веб-страница с несколькими меню. Один из способов написания этого кода — иметь несколько условий if else и выполнять действия при каждом щелчке меню.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
private void getAction(String action){ if (action.equalsIgnoreCase( 'New' )){ //Create new file } else if (action.equalsIgnoreCase( 'Open' )){ //Open existing file } if (action.equalsIgnoreCase( 'Print' )){ //Print the file } if (action.equalsIgnoreCase( 'Exit' )){ //get out of the application } } |
Мы должны выполнить действия, основанные на строке действия. Однако приведенный выше код имеет слишком много условий if и не может быть прочитан, если он распространяется дальше.
Намерение:
- Запросчик действия должен быть отделен от объекта, который выполняет это действие.
- Разрешить инкапсуляцию запроса как объекта. Обратите внимание на эту строку, поскольку это очень важная концепция для шаблона команд.
- Разрешить хранение запросов в очереди, т.е. позволяет хранить список действий, которые вы можете выполнить позже.
Решение:
Чтобы решить вышеупомянутую проблему, шаблон Команды здесь для спасения. Как упоминалось выше, шаблон команды перемещает вышеуказанное действие к объектам посредством инкапсуляции. Эти объекты при выполнении он выполняет команду. Здесь каждая команда является объектом. Поэтому нам придется создавать отдельные классы для каждого из действий меню, таких как NewClass , OpenClass , PrintClass , ExitClass . И все эти классы наследуются от интерфейса Parent, который является интерфейсом Command. Этот интерфейс (командный интерфейс) абстрагирует / переносит все дочерние классы действий.
Теперь мы представляем класс Invoker, основной задачей которого является сопоставление действия с классами, которые имеют это действие. Он в основном содержит действие и получает команду для выполнения запроса, вызывая метод execute ().
К сожалению !! Мы пропустили другого участника здесь. Это класс Receiver. Класс получателя знает, что делать для выполнения операции. Получатель знает, что делать при выполнении действия.
Состав:
Ниже приведены участники шаблона Command Design:
- Команда — это интерфейс для выполнения операции.
- ConcreteCommand — этот класс расширяет интерфейс Command и реализует метод execute. Этот класс создает связь между действием и получателем.
- Клиент — этот класс создает класс ConcreteCommand и связывает его с получателем.
- Invoker — этот класс просит команду выполнить запрос.
- Получатель — этот класс знает, как выполнить операцию.
Пример :
шаги:
- Определите интерфейс Command с помощью сигнатуры метода, например execute (). В приведенном выше примере ActionListenerCommand — это командный интерфейс, имеющий единственный метод execute () .
- Создайте один или несколько производных классов, которые инкапсулируют некоторое подмножество следующего: объект-получатель, метод, который нужно вызвать, аргументы для передачи. В приведенном выше примере ActionOpen и ActionSave являются классами команд Concrete, которые создают привязку между получателем и действием. Класс ActionOpen вызывает метод действия класса получателя (в данном случае класса Document) внутри execute () . Таким образом, заказывая класс получателя, что должно быть сделано.
- Создание объекта Command для каждого отложенного запроса на выполнение.
- Передайте объект Command от создателя призывателю.
- Вызывающий решает, когда выполнить ().
- Клиент создает экземпляр объекта Receiver (Document) и объекта Command и позволяет вызывающей стороне вызывать команду.
Пример кода:
Командный интерфейс:
1
2
3
|
public interface ActionListenerCommand { public void execute(); } |
Класс приемника:
1
2
3
4
5
6
7
8
|
public class Document { public void Open(){ System.out.println( 'Document Opened' ); } public void Save(){ System.out.println( 'Document Saved' ); } } |
Конкретная команда:
01
02
03
04
05
06
07
08
09
10
11
|
public class ActionOpen implements ActionListenerCommand { private Document adoc; public ActionOpen(Document doc) { this .adoc = doc; } @Override public void execute() { adoc.Open(); } } |
Класс Invoker:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public class MenuOptions { private ActionListenerCommand openCommand; private ActionListenerCommand saveCommand; public MenuOptions(ActionListenerCommand open, ActionListenerCommand save) { this .openCommand = open; this .saveCommand = save; } public void clickOpen(){ openCommand.execute(); } public void clickSave(){ saveCommand.execute(); } } |
Класс клиента :
01
02
03
04
05
06
07
08
09
10
11
|
public class Client { public static void main(String[] args) { Document doc = new Document(); ActionListenerCommand clickOpen = new ActionOpen(doc); ActionListenerCommand clickSave = new ActionSave(doc); MenuOptions menu = new MenuOptions(clickOpen, clickSave); menu.clickOpen(); menu.clickSave(); } } |
Выгоды:
Командный шаблон помогает разделить призывателя и получателя. Получатель — тот, кто знает, как выполнить действие.
Команда должна иметь возможность реализовывать операции отмены и возврата.
Этот шаблон помогает с точки зрения расширяемости, поскольку мы можем добавить новую команду без изменения существующего кода.
недостаток:
Основным недостатком шаблона Command является увеличение количества классов для каждой отдельной команды. Эти пункты можно было бы также сделать путем реализации метода. Однако классы шаблонов команд более читабельны, чем создание нескольких методов с использованием условия if else.
Интересные моменты:
- Реализации java.lang.Runnable и javax.swing.Action следует шаблону проектирования команд.
- Команда может использовать Memento для поддержания состояния, необходимого для операции отмены.
Скачать образец кода:
Ссылка: По вашей команде от нашего партнера JCG Майнака Госвами в блоге Idiotechie .