Использование шаблона Command Design

Может ли кто-нибудь объяснить с помощью простого примера Command Pattern. Я говорю в Интернете, но я запутался.

Ответ 1

public interface Command {
   public void execute();
}

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

По моему мнению, я считаю очень важным прислушаться к неизменному контексту команды, иначе команда станет предложением. Например:

public final class StopServerCommand implements Command {
    private final Server server;

    public StopServerCommand(Server server) { this.server = server; }

    public void execute() {
        if(server.isRunning()) server.stop();
    }
}

public class Application {
    //...
    public void someMethod() {
        stopButton.addActionListener(new ActionListener() {
            public void actionPerformed(Event e) {
                 stopCommand.execute();
            }
        });
    }
}

Мне лично не нравятся команды. По моему собственному опыту они хорошо работают только для обратных вызовов Framework.

Если это помогает, подумайте о команде в метафорическом смысле; обученный солдат получает команду от своего командира, и по требованию солдат выполняет эту команду.

Ответ 2

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

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

Диаграмма UML из статьи :

enter image description here

Основные характеристики:

  1. Команда объявляет интерфейс для всех команд, предоставляя простой метод execute(), который просит получателя команды выполнить операцию.

  2. Получатель знает, что делать для выполнения запроса.

  3. Invoker содержит команду и может заставить команду выполнить запрос, вызвав метод execute.

  4. Клиент создает ConcreteCommands и устанавливает получателя для команды.

  5. ConcreteCommand определяет привязку между действием и получателем.

  6. Когда вызовы Invoker выполняются, ConcreteCommand запустит одно или несколько действий на получателе.

Фрагмент кода:

interface Command {
    void execute();
}
interface Receiver {
    public  void switchOn();

}
class OnCommand implements Command{
    private Receiver receiver;

    public OnCommand(Receiver receiver){
        this.receiver = receiver;
    }
    public void execute(){
        receiver.switchOn();
    }
}
class Invoker {
    private Command command;

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

class TV implements Receiver{

     public void switchOn(){
        System.out.println("Switch on from TV");
    }
}
class DVDPlayer implements Receiver{

    public void switchOn(){
         System.out.println("Switch on from DVDPlayer");
    }
}

public class CommandDemoEx{
    public static void main(String args[]){
        // On command for TV with same invoker 
        Receiver receiver = new TV();
        Command onCommand = new OnCommand(receiver);
        Invoker invoker = new Invoker(onCommand);
        invoker.execute();

        // On command for DVDPlayer with same invoker 
        receiver = new DVDPlayer();
        onCommand = new OnCommand(receiver);
        invoker = new Invoker(onCommand);
        invoker.execute();            
    }
}

выход:

Switch on from TV
Switch on from DVDPlayer

Объяснение:

В этом примере

  1. Интерфейс команды определяет метод execute().
  2. OnCommand - это ConcreteCommand, который реализует метод execute().
  3. Receiver - это интерфейс, и разработчики должны обеспечить реализацию методов.
  4. TV и DVDPlayer - это два типа приемников, которые передаются в ConcreteCommand, например, OnCommand.
  5. Invoker содержит команду. Это ключ к отмене привязки отправителя к получателю.
  6. Invoker получает OnCommand ->, который вызывает Receiver (TV) для выполнения этой команды.

Используя Invoker, вы можете включить телевизор и DVDPlayer. Если вы расширили эту программу, вы выключите и телевизор, и DVDPlayer.

Вы можете использовать шаблон Command для

  1. Отсоедините отправителя и получатель команды

  2. Реализовать механизм обратного вызова

  3. Реализовать функции отмены и повтора

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

Ознакомьтесь с этими статьями dzone и journaldev и Википедии.

Исходный код на странице Википедии прост, понятен и не требует пояснений.

Вы можете реализовать Отмена и Повторить, если вы выполните действия, указанные в этой статье.

Ответ 3

Вот еще один пример, который вы можете использовать, чтобы понять, как работает шаблон команды, используя сценарии реальной жизни: вы не можете путешествовать с одного места на другое на самолете без использования шаблона команды!

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

Но если вы это сделаете, ваша команда в администрации аэропорта будет засмеяна! им нужно, чтобы вы предоставили командный объект, который является вашим билетом. насколько вы не заботитесь о том, какая авиакомпания или какой тип самолета, когда вы готовы летать, вам нужно предоставить объект команды билета. Invoker, который является должностным лицом аэропорта, должен проверить вашу команду (билет), чтобы они могли проверить ее, отменить, если это подделка, повторить ее, если они совершили ошибку (без необходимости проходить процесс бронирования по всему),

Короче говоря, они хотят иметь полный контроль над вашей командой (билетом), прежде чем принимать решение о том, следует ли вызывать или выполнять вашу команду, что позволяет авиакомпании (получателю) выполнить (поставить вас на самолет и доставить вас на свой место назначения).

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

У властей аэропорта может даже быть куча билетов, над которыми они работают. они могут выбрать, чтобы отложить мой билет и позволить кому-то, кто пришел за мной, пройти (призывать к билету других лиц раньше моего)

Вот код:

 [TestClass]
    public class Client
    {
        [TestMethod]
        public void MyFlight_UsingCommandPattern()
        {
            var canadianAirline = new Airline();

            AirlineTicket_Command myTicket = new MyAirLineTicket(canadianAirline);

            var airportOfficials = new AirportOfficials_Invoker(myTicket);
            airportOfficials.ProcessPasengerTicket_And_AllowPassengerToFly_Execute();

            //assert not implemented
        }
    }

    public class AirportOfficials_Invoker
    {
        private AirlineTicket_Command PassengerTicket { set; get; }

        public AirportOfficials_Invoker(AirlineTicket_Command passengerTicket)
        {
            throw new NotImplementedException();
        }

        public void ProcessPasengerTicket_And_AllowPassengerToFly_Execute()
        {
            PassengerTicket.Execute();
        }
    }

    public abstract class AirlineTicket_Command
    {
        protected Airline Airline { set; get; }

        protected AirlineTicket_Command(Airline airline)
        {
            Airline = airline;
        }

        public abstract void Execute();
    }

    public class MyAirLineTicket : AirlineTicket_Command
    {
        public MyAirLineTicket(Airline airline)
            : base(airline)
        {
        }

        public override void Execute()
        {
            Airline.FlyPassenger_Action();
        }
    }

    public class Airline
    {
        public void FlyPassenger_Action()
        {
//this will contain all those stuffs of getting on the plane and flying you to your destination
        }
    }

Ответ 4

Моим требованием является выполнение последовательности задач (которые могут быть повторно использованы в нескольких Usecases) каждый со своим собственным потоком исключений. Найдена логическая схема командной строки.

Я пытаюсь сделать так, чтобы каждое действие, выполняемое командой (как обычный, так и альтернативный поток), также могло быть обработчиком исключений. Однако, если команда зарегистрирована другим обработчиком, это должно использоваться. Любые предложения по улучшению/исправлению приветствуются.

public interface Command {
    Result run() throws Exception;
    Command onException(ExceptionHandler handler);
}

public class Result {
}

public interface ExceptionHandler {
    void handleException(Exception e);
}

public interface Action {
    Result execute() throws Exception;
}

public class BasicCommand implements Command {
private Action action;
private ExceptionHandler handler;

public BasicCommand(Action action) {
    if (action == null) {
        throw new IllegalArgumentException("Action must not be null.");
    }
    this.action = action;
    this.handler = (ExceptionHandler) this.action;
}

@Override
public Command onException(ExceptionHandler handler) {
    if (handler != null) {
        this.handler = handler;
    }
    return this;
}

public Result run() throws Exception {
    Result result = null;
    try {
        result = action.execute();
    } catch (Exception e) {
        handler.handleException(e);
    }
    return result;
}

}

public class BasicAction implements Action, ExceptionHandler {
    private Object[] params;


    public BasicAction(Object... params) {
        this.params = params;
    }

    @Override
    public Result execute() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void handleException(Exception e) {
        // TODO exception translation: prepare unchecked application. exception and throw..
    }
}

public class Main {

    public static void main(String[] args) throws Exception {
        int param1 = 10;
        String param2 = "hello";

        // command will use the action itself as an exception handler
        Result result = new BasicCommand(new BasicAction(param1, param2)).run();

        ExceptionHandler myHandler = new ExceptionHandler(){
            @Override
            public void handleException(Exception e) {
                System.out.println("handled by external handler");
            }
        };
        // command with an exception handler passed from outside.
          Result result2 = new BasicCommand(new BasicAction(param1, param2)).onException(myHandler).run();

    }
}

Ответ 5

Шаблоны проектирования команд отменяют вызов оператора сервиса и поставщика услуг. В общем случае, скажем, например, if Object A хочет службу Object B, он будет напрямую вызывать B.requiredService(). Таким образом, A знает о B. В Command pattern эта муфта удаляется. Здесь есть промежуточный объект, известный как Command, который входит в картину. Таким образом, A имеет дело с объектом Command, а объект команды имеет дело с фактическим объектом B. Этот подход имеет несколько приложений, таких как проектирование приложений, которые: -

  • Принимает команды как запросы.
  • Отмена запросов.
  • Запросы запросов.
  • Создание макросов.
  • Создание исполнителей задач и менеджеров задач.

Для получения дополнительной информации относительно шаблона проектирования команд, я рекомендую https://en.wikipedia.org/wiki/Command_pattern. Для всех других шаблонов проектирования см. https://www.u-cursos.cl/usuario/.../mi_blog/r/head_first_design_patterns.pdf

Ответ 6

Я бы попробовал привести здесь еще одну грубую аналогию.

Предположим, что однажды Бог призывает вас и говорит, что мир в опасности, и Ему нужна ваша помощь, чтобы спасти его. Далее, помогая вам, Он говорит вам, что послал несколько супергероев на землю.

Так как Он не знает упс, и, следовательно, Он не называет их супергероями (не предоставляет вам никакого интерфейса или абстрактного класса над ними), а просто назовет их имена для бывшего Бэтмена, Супермена, Железного человека и полномочия у них есть.

Он также говорит, что в будущем Он может отправить больше таких парней в будущем.

Теперь Он возлагает на вас особую ответственность → контролирует их и за это предоставляет вам семь рук. Он не решает задачу каждой руки сам, но оставляет ее на вас.

Вам нужна гибкость в назначении любого ручного контроля над любой силой супергероя и не хотите многократно менять вещи в нескольких условиях.

Вы в исправлении. Что ты сейчас делаешь?

Введите шаблон команды.

Создайте интерфейс Command и используйте только один метод execute(). Инкапсулируйте каждую мощь каждого супергероя и сделайте так, чтобы он реализовывал Command для ex - IronManCreatesSuitCommand

Теперь вы можете назначить любую руку любой команде в любое время, что дает вам большую гибкость, потому что теперь ни одна из ваших рук не заботится о конкретной задаче, которую она должна выполнить. Вы просто назначаете ему любую команду. Он вызывает execute для него, а команда позаботится обо всем остальном.

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