В этом уроке мы узнаем о шаблоне команд, который является важным шаблоном проектирования поведения. Он имеет несколько важных приложений, таких как реализация функций отмены / повтора в текстовых редакторах.
В шаблоне разработки команд имеется объект команды, который находится между объектами отправителя и получателя. Объект отправителя может создать объект команды. Затем объект команды вызывает открытый метод в получателе. И так, объект-отправитель не должен знать о получателе и его открытых методах.
У нас также есть еще один объект, известный как invoker. Вызывающий объект — это объект, ответственный за вызов соответствующего командного объекта для выполнения задачи. Мы также можем использовать менеджер команд, который отслеживает команды, вызывает их и управляет ими.
Почему шаблон проектирования команд?
Есть несколько популярных вариантов использования шаблона команды:
- Хранение и планирование запросов: мы можем представлять наши запросы как объекты команд, которые затем могут быть сохранены в списках, обработаны, поставлены в очередь или завершены в определенное время с помощью триггера событий. Например, функциональность звонка тревоги может быть достигнута путем представления его в качестве объекта команды и выполнения его в триггере события.
- Поддерживает Done / Undone: шаблон команды позволяет нам выполнять или отменять операции, выполняемые командой
Поскольку каждый объект команды поддерживает операцию do / undo, мы можем расширить эту функциональность для разработки операции do / undo для текстового редактора. Идея состоит в том, чтобы иметь два списка объектов команд — историю и список повторов :
- Список истории содержит все команды, которые были выполнены до сих пор
- Список повторов , с другой стороны, хранит команды, которые мы отменили
- Для каждого запроса команды объект команды создается, выполняется и затем добавляется в список истории.
- По запросу отмены мы проверим и вызовем операцию отмены самой последней команды в списке истории, а затем поместим эту команду в список восстановления
- Для операции повтора мы возьмем самую последнюю команду из списка повторов , ту, которую мы недавно отменили, а затем выполним ее и снова переместим в список истории.
Звучит просто верно!
Представление UML:
Мы можем представить шаблон проектирования команды как:
Где мы имеем,
- Команда: интерфейс или абстрактный класс, определяющий операции для объектов команды.
- ConcreteCommand: это конкретные классы, которые содержат фактическую реализацию для конкретной команды
- Receiver: класс команды вызывает получателя для выполнения запрошенной операции
- Invoker: класс, который открыт для клиента. Ответственный за вызов соответствующей команды
Более того, каждый класс команд обычно обеспечивает реализацию этих методов:
- execute (): определяет работу, которая должна быть сделана
- uninecute (): этот метод отвечает за отмену операции
- isReversible (): этот метод должен возвращать true, если команда может быть отменена, иначе false
Пример реализации:
Предположим, мы должны реализовать функцию вырезания-копирования-вставки для текстового редактора.
Итак, начнем с определения нашего интерфейса Command :
1
2
3
4
5
6
7
8
9
|
public interface Command { void execute(); void unexecute(); default boolean isReversible() { return true ; } } |
Также предположим, что у нас есть класс Document, поддерживающий вставку и удаление текста:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
//class which will be our Receiver public class Document { public void insert(String str, int position) { ... } public String delete( int position, int noOfChars) { ... } public void copy( int position, int noOfChars) { ... } } |
Написание конкретных команд:
Теперь мы определим наш класс CutCommand :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public class CutCommand implements Command { private Document doc; private String text; private int startPosition; private int noOfChars; //suitable constructor public void execute() { this .text = this .doc.delete(startPosition, noOfChars); } public void unexecute() { this .doc.insert(text, startPosition); } } |
Давайте также определим два других командных класса:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
public class CopyCommand implements Command { private Document doc; private int startPosition; private int length; //suitable constructor public void execute() { this .doc.copy(startPosition, length); } public void unexecute() { System.out.println( "Uncopy operation is blocked" ); } public boolean isReversible() { return false ; } } public class PasteCommand implements Command { private Document doc; private String text; private int startPosition; //suitable constructor public void execute() { this .doc.insert(text, startPosition); } public void unexecute() { this .doc.delete(startPosition, text.length()); } } |
Как мы знаем, uncopy не является допустимой операцией, мы вернули false в нашем методе isReversible () класса CopyCommand .
Реализация Invoker:
Наконец, мы можем написать класс invoker:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public class DocumentInvoker { private Document document; private CommandManager commandManager; public DocumentInvoker(Document document) { this .document = document; commandManager = CommandManage.getInstance(); } public void cut( int position, int length) { Command cutCommand = new CutCommand(document, position, length); commandManager.invoke(cutCommand); } public void copy( int position, int length) { Command copyCommand = new CopyCommand(document, position, length); commandManager.invoke(copyCommand); } public void paste(String text, int position) { Command pasteCommand = new PasteCommand(document, text, position); commandManager.invoke(pasteCommand); } } |
Здесь CommandManager — это класс, который управляет историей и списками повторов . Вызывающий объект создает экземпляр объекта команды с необходимой ему информацией, а затем вызывает диспетчер команд, чтобы, наконец, выполнить операцию.
Вывод:
В этом уроке мы узнали, как реализовать шаблон проектирования команд в Java.
Это способствует слабой связи, поскольку отправителю не нужно ничего знать о получателе, и он может просто вызывать операции.
Опубликовано на Java Code Geeks с разрешения Шубхры Шриваставы, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Шаблон проектирования команд в Java Мнения, высказанные участниками Java Code Geeks, являются их собственными. |