Использование шаблона Command Design - PullRequest
14 голосов
/ 06 января 2010

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

Ответы [ 5 ]

20 голосов
/ 06 января 2010
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();
            }
        });
    }
}

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

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

7 голосов
/ 14 января 2016

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

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

Диаграмма UML из справочная артикул:

enter image description here

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

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

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

  3. Invoker содержит команду и может Command выполнить запрос, вызвав метод 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 - это два типа Receivers , которые передаются в ConcreteCommand, например, OnCommand.
  5. Invoker содержит Команда . Это ключ к разъединению Отправителя с Получателя .
  6. Invoker получает OnCommand -> который вызывает Receiver (TV) для выполнения этой команды.

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

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

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

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

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

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

Посмотрите на эту dzone и journaldev и Wikipedia статьи.

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

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

6 голосов
/ 27 февраля 2014

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

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

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

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

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

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

Вот код:

 [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
        }
    }
3 голосов
/ 30 марта 2012

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

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

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();

    }
}
0 голосов
/ 10 ноября 2016

Command Design Patterns отделяет инициатора обслуживания и поставщика услуг. В общем случае, например, например, если Object A хочет обслуживать Object B, он будет напрямую вызывать B.requiredService(). Таким образом, A знает о B. В шаблоне Command эта связь удалена. Здесь есть промежуточный объект, известный как 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

...