Использование шаблона проектирования команд

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


person RKCY    schedule 06.01.2010    source источник
comment
en.wikipedia.org/wiki/Command_pattern   -  person z -    schedule 06.01.2010


Ответы (5)


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

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

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

person Droo    schedule 06.01.2010
comment
@Droo, продолжение того, что вам не очень нравится - на самом деле это очень естественная реализация таких вещей, как абстрагирование управления устройством. Например, раньше мне приходилось управлять множеством камер (все они используют разные последовательные протоколы) с помощью общего джойстика. Было очень полезно иметь одну команду для панорамирования, другую для масштабирования и т. д. - person Bob Cross; 06.01.2010
comment
@Droo: можешь объяснить на простом примере? - person RKCY; 10.01.2010
comment
@Droo, где, черт возьми, был создан объект stopCommand? - person Romantic Electron; 01.09.2013

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

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

Схема UML из статьи dofactory:

введите описание изображения здесь

Основные функции:

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

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

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

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

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

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

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

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

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

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

  1. Разделите отправителя и получателя команды

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

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

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

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

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

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

person Ravindra babu    schedule 14.01.2016
comment
Key features:, которое вы здесь написали, очень полезно, по крайней мере, для меня, у вас есть/знаете какой-нибудь блог или что-то в этом роде, чтобы я мог найти такое объяснение для других шаблонов проектирования? Я имею в виду, как вы сделали здесь - person Mehdi Dehghani; 13.10.2019
comment
Вы можете найти другие мои посты о шаблонах проектирования в указанном выше формате. - person Ravindra babu; 13.10.2019

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

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

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

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

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

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

Вот код:

 [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
        }
    }
person Samuel    schedule 27.02.2014

Шаблоны разработки команд разделяют инициатора службы и поставщика службы. В общем случае, скажем, например, если 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

person Mangu Singh Rajpurohit    schedule 10.11.2016

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

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

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

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

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

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

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

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

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

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

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

person vishal    schedule 18.08.2019