Рубрики
Без рубрики

Шаблон проектирования команд

Шаблон команды. Пример шаблона проектирования команд на Java. Пример шаблона команд Java, Диаграмма Классов, Исходный код, Пример из реальной жизни.

Автор оригинала: Pankaj Kumar.

Шаблон команды – это один из шаблонов поведенческого проектирования. Шаблон проектирования команд используется для реализации слабой связи в модели запрос-ответ.

Шаблон команды

В шаблоне команды запрос отправляется вызывающему , а вызывающий передает его инкапсулированному командному объекту.

Объект команды передает запрос соответствующему методу Получателя для выполнения определенного действия.

Клиентская программа создает объект-приемник, а затем присоединяет его к команде. Затем он создает объект-вызыватель и присоединяет объект-команду для выполнения действия.

Теперь, когда клиентская программа выполняет действие, оно обрабатывается на основе команды и объекта получателя.

Пример Шаблона Проектирования команд

Мы рассмотрим сценарий реальной жизни, в котором мы можем реализовать командный шаблон. Допустим, мы хотим предоставить утилиту файловой системы с методами открытия, записи и закрытия файла. Эта утилита файловой системы должна поддерживать несколько операционных систем, таких как Windows и Unix.

Чтобы реализовать нашу утилиту файловой системы, в первую очередь нам нужно создать классы-приемники, которые фактически будут выполнять всю работу.

Поскольку мы кодируем в терминах интерфейса на java , у нас может быть Приемник файловой системы интерфейс и классы его реализации для различных типов операционных систем, таких как Windows, Unix, Solaris и т.д.

Классы Приемников Командных Шаблонов

package com.journaldev.design.command;

public interface FileSystemReceiver {

	void openFile();
	void writeFile();
	void closeFile();
}

Интерфейс приемника файловой системы определяет контракт для классов реализации. Для простоты я создаю два варианта классов приемников для работы с системами Unix и Windows.

package com.journaldev.design.command;

public class UnixFileSystemReceiver implements FileSystemReceiver {

	@Override
	public void openFile() {
		System.out.println("Opening file in unix OS");
	}

	@Override
	public void writeFile() {
		System.out.println("Writing file in unix OS");
	}

	@Override
	public void closeFile() {
		System.out.println("Closing file in unix OS");
	}

}
package com.journaldev.design.command;

public class WindowsFileSystemReceiver implements FileSystemReceiver {

	@Override
	public void openFile() {
		System.out.println("Opening file in Windows OS");
		
	}

	@Override
	public void writeFile() {
		System.out.println("Writing file in Windows OS");
	}

	@Override
	public void closeFile() {
		System.out.println("Closing file in Windows OS");
	}

}

Вы заметили аннотацию переопределения, и если вам интересно, почему она используется, пожалуйста, прочитайте аннотации java и преимущества переопределения аннотаций .

Теперь, когда наши классы приемников готовы, мы можем перейти к реализации наших классов команд.

Интерфейс и реализации шаблонов команд

Мы можем использовать интерфейс или абстрактный класс для создания нашей базовой команды, это дизайнерское решение и зависит от ваших требований.

Мы идем с интерфейсом, потому что у нас нет никаких реализаций по умолчанию.

package com.journaldev.design.command;

public interface Command {

	void execute();
}

Теперь нам нужно создать реализации для всех различных типов действий, выполняемых получателем. Поскольку у нас есть три действия, мы создадим три реализации команд. Каждая реализация команды перенаправит запрос соответствующему методу получателя.

package com.journaldev.design.command;

public class OpenFileCommand implements Command {

	private FileSystemReceiver fileSystem;
	
	public OpenFileCommand(FileSystemReceiver fs){
		this.fileSystem=fs;
	}
	@Override
	public void execute() {
		//open command is forwarding request to openFile method
		this.fileSystem.openFile();
	}

}
package com.journaldev.design.command;

public class CloseFileCommand implements Command {

	private FileSystemReceiver fileSystem;
	
	public CloseFileCommand(FileSystemReceiver fs){
		this.fileSystem=fs;
	}
	@Override
	public void execute() {
		this.fileSystem.closeFile();
	}

}
package com.journaldev.design.command;

public class WriteFileCommand implements Command {

	private FileSystemReceiver fileSystem;
	
	public WriteFileCommand(FileSystemReceiver fs){
		this.fileSystem=fs;
	}
	@Override
	public void execute() {
		this.fileSystem.writeFile();
	}

}

Теперь у нас есть готовые реализации приемника и команды, поэтому мы можем перейти к реализации класса invoker.

Класс Вызывателя командного Шаблона

Invoker-это простой класс, который инкапсулирует команду и передает запрос объекту команды для ее обработки.

package com.journaldev.design.command;

public class FileInvoker {

	public Command command;
	
	public FileInvoker(Command c){
		this.command=c;
	}
	
	public void execute(){
		this.command.execute();
	}
}

Наша реализация утилиты файловой системы готова, и мы можем перейти к написанию простой клиентской программы с шаблоном команд. Но перед этим я предоставлю служебный метод для создания соответствующего Получателя файловой системы объекта.

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

package com.journaldev.design.command;

public class FileSystemReceiverUtil {
	
	public static FileSystemReceiver getUnderlyingFileSystem(){
		 String osName = System.getProperty("os.name");
		 System.out.println("Underlying OS is:"+osName);
		 if(osName.contains("Windows")){
			 return new WindowsFileSystemReceiver();
		 }else{
			 return new UnixFileSystemReceiver();
		 }
	}
	
}

Давайте теперь перейдем к созданию нашей клиентской программы с примером командной строки, которая будет использовать нашу утилиту файловой системы.

package com.journaldev.design.command;

public class FileSystemClient {

	public static void main(String[] args) {
		//Creating the receiver object
		FileSystemReceiver fs = FileSystemReceiverUtil.getUnderlyingFileSystem();
		
		//creating command and associating with receiver
		OpenFileCommand openFileCommand = new OpenFileCommand(fs);
		
		//Creating invoker and associating with Command
		FileInvoker file = new FileInvoker(openFileCommand);
		
		//perform action on invoker object
		file.execute();
		
		WriteFileCommand writeFileCommand = new WriteFileCommand(fs);
		file = new FileInvoker(writeFileCommand);
		file.execute();
		
		CloseFileCommand closeFileCommand = new CloseFileCommand(fs);
		file = new FileInvoker(closeFileCommand);
		file.execute();
	}

}

Обратите внимание, что клиент несет ответственность за создание соответствующего типа объекта команды. Например, если вы хотите записать файл, вы не должны создавать команду Закрыть файл объект.

Клиентская программа также отвечает за подключение приемника к команде, а затем команды к классу вызывающего.

Вывод приведенного выше примера командной программы-это:

Underlying OS is:Mac OS X
Opening file in unix OS
Writing file in unix OS
Closing file in unix OS

Схема классов шаблонов команд

Вот схема классов для реализации утилиты файловой системы.

Важные моменты командной Схемы

  • Команда-это ядро шаблона проектирования команд, определяющего контракт на реализацию.
  • Реализация приемника отделена от реализации команды.
  • Классы реализации команд выбрали метод для вызова объекта receiver, для каждого метода в receiver будет реализована команда. Он работает как мост между приемником и методами действия.
  • Класс вызывающего просто перенаправляет запрос от клиента к объекту команды.
  • Клиент несет ответственность за создание экземпляра соответствующей реализации команды и получателя, а затем за их объединение.
  • Клиент также отвечает за создание экземпляра объекта-вызывателя и связывание с ним объекта-команды и выполнение метода действия.
  • Шаблон проектирования команд легко расширяется, мы можем добавлять новые методы действий в приемниках и создавать новые реализации команд без изменения кода клиента.
  • Недостатком шаблона проектирования команд является то, что код становится огромным и запутанным из-за большого количества методов действий и из-за большого количества ассоциаций.

Пример JDK шаблона проектирования команд

Управляемый интерфейс (java.lang.Запускаемый) и действие качания (javax.swing.Действие) использует шаблон команды.